From 071f24751fc2ffa70bd3f949005fb851cc26e195 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 14 Jan 2020 02:30:47 +0000 Subject: [PATCH 01/85] Bump ts-node from 8.5.4 to 8.6.2 in /web Bumps [ts-node](https://github.com/TypeStrong/ts-node) from 8.5.4 to 8.6.2. - [Release notes](https://github.com/TypeStrong/ts-node/releases) - [Commits](https://github.com/TypeStrong/ts-node/compare/v8.5.4...v8.6.2) Signed-off-by: dependabot-preview[bot] --- web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/package.json b/web/package.json index f76ce3f924..4dfe7340fb 100644 --- a/web/package.json +++ b/web/package.json @@ -52,7 +52,7 @@ "karma-jasmine-html-reporter": "^1.5.1", "node-sass": "^4.13.0", "protractor": "~5.4.2", - "ts-node": "~8.5.4", + "ts-node": "~8.6.2", "tslint": "~5.20.1", "typescript": "3.5.3" } From a4eb07c2accb762aeb22e57a26ca2d82d4e08e90 Mon Sep 17 00:00:00 2001 From: Mikhail Samoylov Date: Mon, 27 Jan 2020 12:56:41 +0300 Subject: [PATCH 02/85] Add prototype checks for cluster and hostprovider. Chech service version. --- tests/functional/test_upgrade_cluster.py | 25 ++++++++++++++++++ .../cluster/config.yaml | 2 +- tests/functional/test_upgrade_hostprovider.py | 26 +++++++++++++++++++ .../upgradable_hostprovider/config.yaml | 4 +-- 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/tests/functional/test_upgrade_cluster.py b/tests/functional/test_upgrade_cluster.py index 6dbd16826c..f8792826c2 100644 --- a/tests/functional/test_upgrade_cluster.py +++ b/tests/functional/test_upgrade_cluster.py @@ -19,6 +19,31 @@ from tests.library.errorcodes import UPGRADE_ERROR +def test_check_prototype(sdk_client_fs: ADCMClient): + """Check prototype for service and cluster after upgrade + :param sdk_client_fs: + :return: + """ + bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'cluster')) + sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgradable_cluster')) + cluster = bundle.cluster_create("test") + cl_id_before = cluster.id + service = cluster.service_add(name="zookeeper") + serv_id_before = service.id + cluster_proto_before = cluster.prototype() + service_proto_before = service.prototype() + upgr = cluster.upgrade(name='upgrade to 1.6') + upgr.do() + cluster.reread() + service.reread() + cluster_proto_after = cluster.prototype() + service_proto_after = service.prototype() + assert cl_id_before == cluster.id + assert serv_id_before == service.id + assert cluster_proto_before.id != cluster_proto_after.id + assert service_proto_before.id != service_proto_after.id + + def test_check_config(sdk_client_fs: ADCMClient): """Check default service and cluster config fields after upgrade :return: diff --git a/tests/functional/test_upgrade_cluster_data/cluster/config.yaml b/tests/functional/test_upgrade_cluster_data/cluster/config.yaml index f72ffb2b2b..c6bbd38dd2 100644 --- a/tests/functional/test_upgrade_cluster_data/cluster/config.yaml +++ b/tests/functional/test_upgrade_cluster_data/cluster/config.yaml @@ -41,4 +41,4 @@ int_key_service: type: integer required: false - default: 150 \ No newline at end of file + default: 150 diff --git a/tests/functional/test_upgrade_hostprovider.py b/tests/functional/test_upgrade_hostprovider.py index 6397621cc8..c603dd2f3d 100644 --- a/tests/functional/test_upgrade_hostprovider.py +++ b/tests/functional/test_upgrade_hostprovider.py @@ -19,6 +19,31 @@ from tests.library.errorcodes import UPGRADE_ERROR +def test_check_prototype(sdk_client_fs: ADCMClient): + """Check prototype for service and cluster after upgrade + :param sdk_client_fs: + :return: + """ + bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'hostprovider')) + sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgradable_hostprovider')) + hostprovider = bundle.provider_create("test") + host = hostprovider.host_create(fqdn="localhost") + hostprovider_proto_before = hostprovider.prototype() + hp_id_before = hostprovider.id + host_proto_before = host.prototype() + ht_id_before = host.id + upgr = hostprovider.upgrade(name='upgrade to 2.0') + upgr.do() + hostprovider.reread() + host.reread() + hostprovider_proto_after = hostprovider.prototype() + host_proto_after = host.prototype() + assert hp_id_before == hostprovider.id + assert ht_id_before == host.id + assert hostprovider_proto_before.id != hostprovider_proto_after.id + assert host_proto_before.id != host_proto_after.id + + def test_check_config(sdk_client_fs: ADCMClient): """Check default host and hostprovider config fields after upgrade :return: @@ -36,6 +61,7 @@ def test_check_config(sdk_client_fs: ADCMClient): hostprovider_config_after = hostprovider.config() host_config_after = host.config() assert hostprovider.prototype().version == '2.0' + assert host.prototype().version == '00.10' for variable in hostprovider_config_before: assert hostprovider_config_before[variable] == hostprovider_config_after[variable] for variable in host_config_before: diff --git a/tests/functional/test_upgrade_hostprovider_data/upgradable_hostprovider/config.yaml b/tests/functional/test_upgrade_hostprovider_data/upgradable_hostprovider/config.yaml index 166af71e85..28dccb41c5 100644 --- a/tests/functional/test_upgrade_hostprovider_data/upgradable_hostprovider/config.yaml +++ b/tests/functional/test_upgrade_hostprovider_data/upgradable_hostprovider/config.yaml @@ -63,7 +63,7 @@ - type: host name: vHost - version: 00.09 + version: '00.10' config: str_param: @@ -75,4 +75,4 @@ type: integer required: false default: 2 - description: must be changed to 5 \ No newline at end of file + description: must be changed to 5 From 90e9757fc285c2684ff3f1bee58ec151d80a178f Mon Sep 17 00:00:00 2001 From: Mikhail Samoylov Date: Mon, 27 Jan 2020 20:51:43 +0300 Subject: [PATCH 03/85] Full cluster and hostprovider updates. Upgrade when we have attached to host component for cluster. Check both upgrade orders cluster upgrade first and hostprovider upgrade first. --- tests/functional/test_full_upgrade.py | 72 +++++++++++++++++ .../cluster/config.yaml | 50 ++++++++++++ .../hostprovider/config.yaml | 57 ++++++++++++++ .../upgradable_cluster/config.yaml | 65 ++++++++++++++++ .../upgradable_hostprovider/config.yaml | 78 +++++++++++++++++++ 5 files changed, 322 insertions(+) create mode 100644 tests/functional/test_full_upgrade.py create mode 100644 tests/functional/test_full_upgrade_data/cluster/config.yaml create mode 100644 tests/functional/test_full_upgrade_data/hostprovider/config.yaml create mode 100644 tests/functional/test_full_upgrade_data/upgradable_cluster/config.yaml create mode 100644 tests/functional/test_full_upgrade_data/upgradable_hostprovider/config.yaml diff --git a/tests/functional/test_full_upgrade.py b/tests/functional/test_full_upgrade.py new file mode 100644 index 0000000000..f71110abc4 --- /dev/null +++ b/tests/functional/test_full_upgrade.py @@ -0,0 +1,72 @@ +# 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. +# pylint: disable=W0611, W0621 +from adcm_client.objects import ADCMClient +from adcm_pytest_plugin.utils import get_data_dir + + +def test_full_upgrade_hostprovider_first(sdk_client_fs: ADCMClient): + """Create cluster and hostprovider with host and components and upgrade cluster and host with provider after that + and check that all was upgraded. + """ + bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'cluster')) + sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgradable_cluster')) + cluster = bundle.cluster_create("test") + service = cluster.service_add(name="zookeeper") + comp = service.component(name='master') + hp_bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'hostprovider')) + sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgradable_hostprovider')) + hostprovider = hp_bundle.provider_create("test") + host = hostprovider.host_create(fqdn="localhost") + cluster.host_add(host) + cluster.hostcomponent_set((host, comp)) + upgr_hp = hostprovider.upgrade(name='upgrade to 2.0') + upgr_hp.do() + upgr_cl = cluster.upgrade(name='upgrade to 1.6') + upgr_cl.do() + cluster.reread() + service.reread() + hostprovider.reread() + host.reread() + assert cluster.prototype().version == '1.6' + assert service.prototype().version == '3.4.11' + assert hostprovider.prototype().version == '2.0' + assert host.prototype().version == '00.10' + + +def test_full_upgrade_cluster_first(sdk_client_fs: ADCMClient): + """Create cluster and hostprovider with host and components and upgrade cluster and host with provider after that + and check that all was upgraded. + """ + bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'cluster')) + sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgradable_cluster')) + cluster = bundle.cluster_create("test") + service = cluster.service_add(name="zookeeper") + comp = service.component(name='master') + hp_bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'hostprovider')) + sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgradable_hostprovider')) + hostprovider = hp_bundle.provider_create("test") + host = hostprovider.host_create(fqdn="localhost") + cluster.host_add(host) + cluster.hostcomponent_set((host, comp)) + upgr_cl = cluster.upgrade(name='upgrade to 1.6') + upgr_cl.do() + upgr_hp = hostprovider.upgrade(name='upgrade to 2.0') + upgr_hp.do() + cluster.reread() + service.reread() + hostprovider.reread() + host.reread() + assert cluster.prototype().version == '1.6' + assert service.prototype().version == '3.4.11' + assert hostprovider.prototype().version == '2.0' + assert host.prototype().version == '00.10' diff --git a/tests/functional/test_full_upgrade_data/cluster/config.yaml b/tests/functional/test_full_upgrade_data/cluster/config.yaml new file mode 100644 index 0000000000..b3c21b9c0c --- /dev/null +++ b/tests/functional/test_full_upgrade_data/cluster/config.yaml @@ -0,0 +1,50 @@ +# 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. +- + type: cluster + name: ADH + version: 1.5 + config: + required: + type: integer + required: true + default: 15 + str-key: + default: value + type: string + required: false + + int_key: + type: integer + required: false + default: 150 + + +- type: service + name: zookeeper + version: '3.4.10' + config: + required_service: + type: integer + required: true + default: 10 + + int_key_service: + type: integer + required: false + default: 150 + + components: + master: + display_name: "Master Node" + description: "This node control all data nodes (see below)" + constraint: [1,2] diff --git a/tests/functional/test_full_upgrade_data/hostprovider/config.yaml b/tests/functional/test_full_upgrade_data/hostprovider/config.yaml new file mode 100644 index 0000000000..c508d55bf7 --- /dev/null +++ b/tests/functional/test_full_upgrade_data/hostprovider/config.yaml @@ -0,0 +1,57 @@ +# 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. + +- + + type: provider + name: sample hostprovider + version: 1.0 + config: + required: + type: integer + required: yes + default: 400 + str-key: + default: value + type: string + required: false + + int_key: + type: integer + required: NO + default: 60 + + fkey: + type: float + required: false + default: 1.5 + + bool: + type: boolean + required : no + default: false + +- type: host + name: vHost + version: '00.09' + + config: + str_param: + type: string + required: false + default: '123' + description: must be changed to bar() + int: + type: integer + required: false + default: 2 + description: must be changed to 5 diff --git a/tests/functional/test_full_upgrade_data/upgradable_cluster/config.yaml b/tests/functional/test_full_upgrade_data/upgradable_cluster/config.yaml new file mode 100644 index 0000000000..07eb615038 --- /dev/null +++ b/tests/functional/test_full_upgrade_data/upgradable_cluster/config.yaml @@ -0,0 +1,65 @@ +# 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. +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + config: + required: + type: integer + required: true + default: 15 + str-key: + default: value + type: string + required: false + + int_key: + type: integer + required: false + default: 150 + +- type: service + name: zookeeper + version: '3.4.11' + config: + required_service: + type: integer + required: true + default: 10 + + int_key_service: + type: integer + required: false + default: 150 + components: + master: + display_name: "Master Node" + description: "This node control all data nodes (see below)" + constraint: [1,2] diff --git a/tests/functional/test_full_upgrade_data/upgradable_hostprovider/config.yaml b/tests/functional/test_full_upgrade_data/upgradable_hostprovider/config.yaml new file mode 100644 index 0000000000..28dccb41c5 --- /dev/null +++ b/tests/functional/test_full_upgrade_data/upgradable_hostprovider/config.yaml @@ -0,0 +1,78 @@ +# 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. + +- + + type: provider + name: sample hostprovider + version: 2.0 + upgrade: + - + versions: + min: 0.4 + max: 1.9 + description: New cool upgrade + name: upgrade to 2.0 + states: + available: any + on_success: started + - + versions: + min: 1.0 + max: 2.9 + description: Super new upgrade + name: upgrade 2 + states: + available: [started] + on_success: ver2.4 + config: + required: + type: integer + required: yes + default: 400 + max: 500 + min: 200 + str-key: + default: value + type: string + required: false + + int_key: + type: integer + required: NO + default: 60 + + fkey: + type: float + required: false + default: 1.5 + + bool: + type: boolean + required : no + default: false + +- type: host + name: vHost + version: '00.10' + + config: + str_param: + type: string + required: false + default: '123' + description: must be changed to bar() + int: + type: integer + required: false + default: 2 + description: must be changed to 5 From 0252c90b0fcbccf3a924e3bf7f46d0298e604b79 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Tue, 28 Jan 2020 13:00:46 +0300 Subject: [PATCH 04/85] ADCM-1106 config structure analysis --- .../shared/configuration/YspecStructure.ts | 27 ++++++++++++++-- .../configuration/field.service.spec.ts | 31 +++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 web/src/app/shared/configuration/field.service.spec.ts diff --git a/web/src/app/shared/configuration/YspecStructure.ts b/web/src/app/shared/configuration/YspecStructure.ts index 55a948434c..9a143ff546 100644 --- a/web/src/app/shared/configuration/YspecStructure.ts +++ b/web/src/app/shared/configuration/YspecStructure.ts @@ -40,6 +40,27 @@ export class YspecStructure { this.output = this[this.yspec.root.match](options); } + list(source: FieldOptions) { + let scheme = { ...source.limits.yspec }; + + const root = scheme['root'], + value = typeof source.value === 'object' ? source.value : typeof source.default === 'object' ? source.default : null; + + const item = root.item; + const rule = scheme[item]; + + if (rule.match === 'dict') { + return { + ...source, + type: 'group', + options: this.getFields(source, item), + limits: { + yspec: scheme + } + }; + } + } + dict(source: FieldOptions) { return { ...source, @@ -94,11 +115,13 @@ export class YspecStructure { options: this.getFields(source, items[k]), limits: { yspec: scheme - }, + } }; } }); + } else { + console.warn('Yspec :: Items not found'); + return []; } } - } diff --git a/web/src/app/shared/configuration/field.service.spec.ts b/web/src/app/shared/configuration/field.service.spec.ts new file mode 100644 index 0000000000..027ee8ae1f --- /dev/null +++ b/web/src/app/shared/configuration/field.service.spec.ts @@ -0,0 +1,31 @@ +// 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. +import { TestBed } from '@angular/core/testing'; + +import { FieldService } from './field.service'; +import { FormBuilder } from '@angular/forms'; + +describe('Configuration fields service', () => { + let service: FieldService; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [FormBuilder, FieldService] + }); + + service = TestBed.get(FieldService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); From e25bcce65ef1def5ab5df0ad001874f9c667921b Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Tue, 28 Jan 2020 19:14:32 +0300 Subject: [PATCH 05/85] ADCM-1106 yspec structure for configs --- web/src/app/shared/configuration/YspecStructure.ts | 4 ++-- web/src/app/shared/configuration/field.service.ts | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/web/src/app/shared/configuration/YspecStructure.ts b/web/src/app/shared/configuration/YspecStructure.ts index 9a143ff546..8101296724 100644 --- a/web/src/app/shared/configuration/YspecStructure.ts +++ b/web/src/app/shared/configuration/YspecStructure.ts @@ -52,8 +52,8 @@ export class YspecStructure { if (rule.match === 'dict') { return { ...source, - type: 'group', - options: this.getFields(source, item), + type: 'map', + controlType: 'map', limits: { yspec: scheme } diff --git a/web/src/app/shared/configuration/field.service.ts b/web/src/app/shared/configuration/field.service.ts index 89070f82ca..0e09ca8f01 100644 --- a/web/src/app/shared/configuration/field.service.ts +++ b/web/src/app/shared/configuration/field.service.ts @@ -185,7 +185,8 @@ export class FieldService { }, json: (value: string) => (value === null ? '' : JSON.stringify(value, undefined, 4)), map: (value: object, de: object) => (!value ? (!de ? {} : de) : value), - list: (value: string[], de: string[]) => (!value ? (!de ? [] : de) : value) + list: (value: string[], de: string[]) => (!value ? (!de ? [] : de) : value), + structure: (value: any) => value }; return data[name] ? data[name] : def; From 915d85cac598de3e5b9f3663d0b6b53db0cd4742 Mon Sep 17 00:00:00 2001 From: Mikhail Samoylov Date: Wed, 29 Jan 2020 14:19:59 +0300 Subject: [PATCH 06/85] Upgrade tests. Upgrade cluster with imports. --- .../test_upgrade_cluster_imports.py | 89 +++++++++++++++++++ .../cluster_with_export/config.yaml | 54 +++++++++++ .../config.yaml | 41 +++++++++ .../config.yaml | 41 +++++++++ .../upgrade_cluster_with_export/config.yaml | 56 ++++++++++++ .../upgrade_cluster_with_import/config.yaml | 27 ++++++ 6 files changed, 308 insertions(+) create mode 100644 tests/functional/test_upgrade_cluster_imports.py create mode 100644 tests/functional/test_upgrade_cluster_imports_data/cluster_with_export/config.yaml create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_import/config.yaml create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/config.yaml create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgrade_cluster_with_export/config.yaml create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgrade_cluster_with_import/config.yaml diff --git a/tests/functional/test_upgrade_cluster_imports.py b/tests/functional/test_upgrade_cluster_imports.py new file mode 100644 index 0000000000..f6ce610b40 --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports.py @@ -0,0 +1,89 @@ +# 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. +# pylint: disable=W0611, W0621 +import coreapi +import pytest + +from adcm_client.objects import ADCMClient +from adcm_pytest_plugin.utils import get_data_dir + + +def test_upgrade_cluster_with_import(sdk_client_fs: ADCMClient): + """Scenario: + 1. Create cluster for upgrade with exports + 2. Create upgradable cluster with imports + 3. Bind service and cluster + 4. Upgrade cluster + 5. Check that cluster was upgraded + """ + bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgrade_cluster_with_export')) + bundle_import = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgradable_cluster_with_import')) + cluster = bundle.cluster_create("test") + service = cluster.service_add(name="hadoop") + cluster_config_before = cluster.config() + service_config_before = service.config() + cluster_import = bundle_import.cluster_create("cluster_import") + cluster_import.bind(service) + cluster_import.bind(cluster) + upgr = cluster.upgrade(name='upgrade to 1.6') + upgr.do() + cluster.reread() + cluster_config_after = cluster.config() + service_config_after = service.config() + assert cluster.prototype().version == '1.6' + for variable in cluster_config_before: + assert cluster_config_before[variable] == cluster_config_after[variable] + for variable in service_config_before: + assert service_config_before[variable] == service_config_after[variable] + + +def test_upgrade_cluster_with_export(sdk_client_fs: ADCMClient): + """Scenario: + 1. Create cluster for upgrade with export + 2. Create cluster for upgrade with import + 3. Load upgradable bundle with import + 4. Bind service and cluster + 5. Upgrade cluster with import + 6. Check that cluster was upgraded + """ + bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'cluster_with_export')) + bundle_import = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgrade_cluster_with_import')) + sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgradable_cluster_with_import')) + cluster = bundle.cluster_create("test") + service = cluster.service_add(name="hadoop") + cluster_import = bundle_import.cluster_create("cluster_import") + cluster_import.bind(service) + cluster_import.bind(cluster) + upgr = cluster_import.upgrade(name='upgrade to 1.6') + id_before = cluster_import.prototype_id + upgr.do() + cluster_import.reread() + assert cluster_import.prototype().version == '1.6' + assert cluster_import.prototype_id != id_before + + +def test_incorrect_import_version(sdk_client_fs: ADCMClient): + """Upgrade cluster with service incorrect version + + :param sdk_client_fs: + :return: + """ + bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgrade_cluster_with_export')) + bundle_import = sdk_client_fs.upload_from_fs(get_data_dir( + __file__, 'upgradable_cluster_with_incorrect_version')) + cluster = bundle.cluster_create("test") + service = cluster.service_add(name="hadoop") + cluster_import = bundle_import.cluster_create("cluster_import") + cluster_import.bind(service) + cluster_import.bind(cluster) + upgr = cluster.upgrade(name='upgrade to 1.6') + upgr.do() diff --git a/tests/functional/test_upgrade_cluster_imports_data/cluster_with_export/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/cluster_with_export/config.yaml new file mode 100644 index 0000000000..912072acdc --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/cluster_with_export/config.yaml @@ -0,0 +1,54 @@ +# 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. +- + type: cluster + name: ADH + version: 1.0 + config: + required: + type: integer + required: true + default: 15 + str-key: + default: value + type: string + required: false + + int_key: + type: integer + required: false + default: 150 + + export: + - required + - str-key + - int_key + +- type: service + name: hadoop + version: 2.1 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 + + export: + - core-site + - quorum diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_import/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_import/config.yaml new file mode 100644 index 0000000000..429a62000e --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_import/config.yaml @@ -0,0 +1,41 @@ +# 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. +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min: 1.8 + max: 2.5 + ADH: + versions: + min: 1.0 + max: 2.0 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/config.yaml new file mode 100644 index 0000000000..d1549df0b2 --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/config.yaml @@ -0,0 +1,41 @@ +# 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. +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min: 2.2 + max: 2.5 + ADH: + versions: + min: 2.0 + max: 4.0 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgrade_cluster_with_export/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgrade_cluster_with_export/config.yaml new file mode 100644 index 0000000000..41fe71b414 --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgrade_cluster_with_export/config.yaml @@ -0,0 +1,56 @@ +# 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. +--- +- type: service + name: hadoop + version: 2.1 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 + + export: + - core-site + - quorum + +- type: cluster + name: ADH + description: Arenadata Nothing + version: 1.0 + + config: + required: + type: integer + required: true + default: 15 + str-key: + default: value + type: string + required: false + + int_key: + type: integer + required: false + default: 150 + + export: + - required + - str-key + - int_key diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgrade_cluster_with_import/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgrade_cluster_with_import/config.yaml new file mode 100644 index 0000000000..107f50160b --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgrade_cluster_with_import/config.yaml @@ -0,0 +1,27 @@ +# 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. +--- + +- type: cluster + name: ADH + description: Arenadata Nothing + version: 1.1 + + import: + hadoop: + versions: + min: 1.8 + max: 2.5 + ADH: + versions: + min: 1.0 + max: 2.0 From 3d2157e4739907233f91518eac593d378ac20d88 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Wed, 29 Jan 2020 19:28:15 +0300 Subject: [PATCH 07/85] ADCM-1106 UI config structure - list#1 --- web/src/app/core/types/func.ts | 6 +- .../shared/configuration/YspecStructure.ts | 98 ++++++++++++++++--- .../app/shared/configuration/field.service.ts | 8 +- 3 files changed, 91 insertions(+), 21 deletions(-) diff --git a/web/src/app/core/types/func.ts b/web/src/app/core/types/func.ts index 29008aaa24..eb92478337 100644 --- a/web/src/app/core/types/func.ts +++ b/web/src/app/core/types/func.ts @@ -25,11 +25,11 @@ export function controlType(name: string): string { const ControlsTypes = { bool: 'boolean', int: 'textbox', - file: 'textarea', - text: 'textarea', integer: 'textbox', float: 'textbox', - string: 'textbox' + string: 'textbox', + file: 'textarea', + text: 'textarea' }; return ControlsTypes[name] || name; } diff --git a/web/src/app/shared/configuration/YspecStructure.ts b/web/src/app/shared/configuration/YspecStructure.ts index 8101296724..23e5cf2fcf 100644 --- a/web/src/app/shared/configuration/YspecStructure.ts +++ b/web/src/app/shared/configuration/YspecStructure.ts @@ -11,15 +11,17 @@ // limitations under the License. import { controlType, getPattern } from '@app/core/types'; -import { FieldOptions, PanelOptions } from './types'; +import { FieldOptions, PanelOptions, ConfigValueTypes } from './types'; -type matchType = 'string' | 'int' | 'float' | 'bool' | 'list' | 'dict'; +type simpleType = 'string' | 'integer' | 'float' | 'bool'; +type reqursionType = 'list' | 'dict'; +type matchType = simpleType | reqursionType; interface Iroot { match: matchType; selector?: string; variants?: { [key: string]: string }; - item?: string | matchType; + item?: string; items?: { [key: string]: string }; required_items?: string[]; default_item?: string; @@ -29,6 +31,54 @@ export interface IYspec { [key: string]: Iroot; } +class Field { + private _options: Partial; + constructor(public key: string, private value: simpleType) { + this._options = { + display_name: this.key, + name: this.key, + key: this.key, + subname: null, + controlType: controlType(this.value), + type: this.value as ConfigValueTypes, + validator: { + required: true, + pattern: getPattern(this.value) + }, + hidden: false, + read_only: false, + compare: [] + }; + } + get options() { + return this._options; + } + setKey(key: string) { + this._options.key = `${this.key}/${key}`; + return this; + } + setValue(value: simpleType) { + this._options.default = value; + this._options.value = value; + return this; + } +} + +class Group { + constructor(public key: string, private value: reqursionType) {} + options(value: simpleType) { + return {}; + } + setValue(value: simpleType) { + // this.options.default = value; + // this.options.value = value; + return this; + } + setKey(key: string) { + return this; + } +} + export class YspecStructure { yspec: IYspec; source: FieldOptions; @@ -40,23 +90,47 @@ export class YspecStructure { this.output = this[this.yspec.root.match](options); } + getModel(rules: { [key: string]: string }) { + return Object.keys(rules).map(key => { + const value = rules[key]; + if (value as simpleType) return new Field(key, value); + else return new Group(key, value); + }); + } + list(source: FieldOptions) { - let scheme = { ...source.limits.yspec }; + const scheme = { ...source.limits.yspec }; - const root = scheme['root'], - value = typeof source.value === 'object' ? source.value : typeof source.default === 'object' ? source.default : null; + const value = Array.isArray(source.value) ? source.value : Array.isArray(source.default) ? source.default : null; - const item = root.item; + const item = scheme.root.item; const rule = scheme[item]; if (rule.match === 'dict') { + const model = this.getModel(rule.items); + /** + * fill the model to data (value or default) + */ return { ...source, - type: 'map', - controlType: 'map', - limits: { - yspec: scheme - } + type: 'group', + options: value.map((v, i) => { + if (typeof v === 'object') { + return { + display_name: `--- ${i} ---`, + name: i, + key: `${i}/${source.key}`, + type: 'group', + options: Object.keys(v).map( + k => + model + .find(m => m.key === k) + .setKey(`${i}/${source.key}`) + .setValue(v[k]).options + ) + }; + } + }) }; } } diff --git a/web/src/app/shared/configuration/field.service.ts b/web/src/app/shared/configuration/field.service.ts index 0e09ca8f01..6ca30b07cf 100644 --- a/web/src/app/shared/configuration/field.service.ts +++ b/web/src/app/shared/configuration/field.service.ts @@ -57,9 +57,6 @@ export class FieldService { } checkYspec(a: FieldOptions): FieldOptions | PanelOptions { - /** - * Very important for build tree - */ a.name = a.subname || a.name; if (a.limits && a.limits.yspec) { @@ -185,8 +182,7 @@ export class FieldService { }, json: (value: string) => (value === null ? '' : JSON.stringify(value, undefined, 4)), map: (value: object, de: object) => (!value ? (!de ? {} : de) : value), - list: (value: string[], de: string[]) => (!value ? (!de ? [] : de) : value), - structure: (value: any) => value + list: (value: string[], de: string[]) => (!value ? (!de ? [] : de) : value) }; return data[name] ? data[name] : def; @@ -221,7 +217,7 @@ export class FieldService { } findField(name: string, parentName?: string): FieldStack { - return this.globalConfig.config.find(a => a.name === name || (a.name === parentName && a.subname === name)); + return this.globalConfig.config.find(a => (parentName ? a.name === parentName && a.subname === name : a.name === name)); } runYspecParse(value: any, field: FieldStack) { From fdaec83a61fc971b1c5b0c6112f1b0b18ae2ad33 Mon Sep 17 00:00:00 2001 From: Mikhail Samoylov Date: Thu, 30 Jan 2020 16:02:28 +0300 Subject: [PATCH 08/85] New imports tests. --- .../test_upgrade_cluster_imports.py | 51 ++++++++++++ .../config.yaml | 30 +++++++ .../config.yaml | 79 +++++++++++++++++++ .../config.yaml | 18 ++++- .../config.yaml | 41 ++++++++++ 5 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_import_new_config_vars/config.yaml create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_without_service/config.yaml diff --git a/tests/functional/test_upgrade_cluster_imports.py b/tests/functional/test_upgrade_cluster_imports.py index f6ce610b40..23eaf08c02 100644 --- a/tests/functional/test_upgrade_cluster_imports.py +++ b/tests/functional/test_upgrade_cluster_imports.py @@ -15,6 +15,7 @@ from adcm_client.objects import ADCMClient from adcm_pytest_plugin.utils import get_data_dir +from tests.library import errorcodes as err def test_upgrade_cluster_with_import(sdk_client_fs: ADCMClient): @@ -37,9 +38,11 @@ def test_upgrade_cluster_with_import(sdk_client_fs: ADCMClient): upgr = cluster.upgrade(name='upgrade to 1.6') upgr.do() cluster.reread() + service.reread() cluster_config_after = cluster.config() service_config_after = service.config() assert cluster.prototype().version == '1.6' + assert service.prototype().version == '2.2' for variable in cluster_config_before: assert cluster_config_before[variable] == cluster_config_after[variable] for variable in service_config_before: @@ -86,4 +89,52 @@ def test_incorrect_import_version(sdk_client_fs: ADCMClient): cluster_import.bind(service) cluster_import.bind(cluster) upgr = cluster.upgrade(name='upgrade to 1.6') + with pytest.raises(coreapi.exceptions.ErrorMessage) as e: + upgr.do() + err.UPGRADE_ERROR.equal(e) + + +@pytest.mark.xfail(reason="ADCM-1113") +def test_upgrade_cluster_without_service_config_in_import(sdk_client_fs: ADCMClient): + """Upgrade cluster with service when in new cluster we haven't some service configuration variables + """ + bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgrade_cluster_with_export')) + bundle_import = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgradable_cluster_without_service')) + cluster = bundle.cluster_create("test") + service = cluster.service_add(name="hadoop") + cluster_import = bundle_import.cluster_create("cluster_import") + cluster_import.bind(service) + cluster_import.bind(cluster) + upgr = cluster.upgrade(name='upgrade to 1.6') + with pytest.raises(coreapi.exceptions.ErrorMessage) as e: + upgr.do() + err.UPGRADE_ERROR.equal(e) + + +def test_upgrade_cluster_with_new_configuration_variables(sdk_client_fs: ADCMClient): + """Upgrade to cluster with new configuration variables + """ + bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgrade_cluster_with_export')) + bundle_import = sdk_client_fs.upload_from_fs(get_data_dir( + __file__, 'upgradable_cluster_with_import_new_config_vars')) + cluster = bundle.cluster_create("test") + service = cluster.service_add(name="hadoop") + cluster_config_before = cluster.config() + service_config_before = service.config() + cluster_import = bundle_import.cluster_create("cluster_import") + cluster_import.bind(service) + cluster_import.bind(cluster) + upgr = cluster.upgrade(name='upgrade to 1.6') upgr.do() + cluster.reread() + service.reread() + cluster_config_after = cluster.config() + service_config_after = service.config() + assert cluster.prototype().version == '1.6' + assert service.prototype().version == '2.2' + assert len(cluster_config_after) == 4, cluster_config_after + assert len(service_config_after) == 3, service_config_after + for variable in cluster_config_before: + assert cluster_config_before[variable] == cluster_config_after[variable] + for variable in service_config_before: + assert service_config_before[variable] == service_config_after[variable] diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_import/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_import/config.yaml index 429a62000e..e5e70867b5 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_import/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_import/config.yaml @@ -30,6 +30,20 @@ states: available: [created, installed, upgradable] on_success: upgradated + config: + required: + type: integer + required: true + default: 15 + str-key: + default: value + type: string + required: false + + int_key: + type: integer + required: false + default: 150 import: hadoop: versions: @@ -39,3 +53,19 @@ versions: min: 1.0 max: 2.0 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_import_new_config_vars/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_import_new_config_vars/config.yaml new file mode 100644 index 0000000000..fe36260806 --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_import_new_config_vars/config.yaml @@ -0,0 +1,79 @@ +# 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. +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + config: + required: + type: integer + required: true + default: 15 + str-key: + default: value + type: string + required: false + + int_key: + type: integer + required: false + default: 150 + str-key2: + default: value + type: string + required: false + import: + hadoop: + versions: + min: 1.8 + max: 2.5 + ADH: + versions: + min: 1.0 + max: 2.0 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 + serv_int_key: + type: integer + required: false + default: 150 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/config.yaml index d1549df0b2..b98152e0b3 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/config.yaml @@ -33,9 +33,25 @@ import: hadoop: versions: - min: 2.2 + min: 2.3 max: 2.5 ADH: versions: min: 2.0 max: 4.0 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_without_service/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_without_service/config.yaml new file mode 100644 index 0000000000..429a62000e --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_without_service/config.yaml @@ -0,0 +1,41 @@ +# 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. +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min: 1.8 + max: 2.5 + ADH: + versions: + min: 1.0 + max: 2.0 From 938e6ec6bb84bace6bde67a514fa8f4cee54e18f Mon Sep 17 00:00:00 2001 From: Mikhail Samoylov Date: Thu, 30 Jan 2020 19:20:45 +0300 Subject: [PATCH 09/85] Fix linter issues. --- tests/functional/test_full_upgrade.py | 6 ++++-- tests/functional/test_upgrade_cluster_imports.py | 15 ++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/tests/functional/test_full_upgrade.py b/tests/functional/test_full_upgrade.py index f71110abc4..ac33ea405c 100644 --- a/tests/functional/test_full_upgrade.py +++ b/tests/functional/test_full_upgrade.py @@ -15,7 +15,8 @@ def test_full_upgrade_hostprovider_first(sdk_client_fs: ADCMClient): - """Create cluster and hostprovider with host and components and upgrade cluster and host with provider after that + """Create cluster and hostprovider with host and components + and upgrade cluster and host with provider after that and check that all was upgraded. """ bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'cluster')) @@ -44,7 +45,8 @@ def test_full_upgrade_hostprovider_first(sdk_client_fs: ADCMClient): def test_full_upgrade_cluster_first(sdk_client_fs: ADCMClient): - """Create cluster and hostprovider with host and components and upgrade cluster and host with provider after that + """Create cluster and hostprovider with host and components + and upgrade cluster and host with provider after that and check that all was upgraded. """ bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'cluster')) diff --git a/tests/functional/test_upgrade_cluster_imports.py b/tests/functional/test_upgrade_cluster_imports.py index 23eaf08c02..3b1dd01be5 100644 --- a/tests/functional/test_upgrade_cluster_imports.py +++ b/tests/functional/test_upgrade_cluster_imports.py @@ -26,8 +26,10 @@ def test_upgrade_cluster_with_import(sdk_client_fs: ADCMClient): 4. Upgrade cluster 5. Check that cluster was upgraded """ - bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgrade_cluster_with_export')) - bundle_import = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgradable_cluster_with_import')) + bundle = sdk_client_fs.upload_from_fs(get_data_dir( + __file__, 'upgrade_cluster_with_export')) + bundle_import = sdk_client_fs.upload_from_fs(get_data_dir( + __file__, 'upgradable_cluster_with_import')) cluster = bundle.cluster_create("test") service = cluster.service_add(name="hadoop") cluster_config_before = cluster.config() @@ -59,7 +61,8 @@ def test_upgrade_cluster_with_export(sdk_client_fs: ADCMClient): 6. Check that cluster was upgraded """ bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'cluster_with_export')) - bundle_import = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgrade_cluster_with_import')) + bundle_import = sdk_client_fs.upload_from_fs(get_data_dir( + __file__, 'upgrade_cluster_with_import')) sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgradable_cluster_with_import')) cluster = bundle.cluster_create("test") service = cluster.service_add(name="hadoop") @@ -96,10 +99,12 @@ def test_incorrect_import_version(sdk_client_fs: ADCMClient): @pytest.mark.xfail(reason="ADCM-1113") def test_upgrade_cluster_without_service_config_in_import(sdk_client_fs: ADCMClient): - """Upgrade cluster with service when in new cluster we haven't some service configuration variables + """Upgrade cluster with service when in new cluster + we haven't some service configuration variables """ bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgrade_cluster_with_export')) - bundle_import = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgradable_cluster_without_service')) + bundle_import = sdk_client_fs.upload_from_fs(get_data_dir( + __file__, 'upgradable_cluster_without_service')) cluster = bundle.cluster_create("test") service = cluster.service_add(name="hadoop") cluster_import = bundle_import.cluster_create("cluster_import") From 80958184f0745fc573faddebe22d3f2f526d3963 Mon Sep 17 00:00:00 2001 From: Anton Chevychalov Date: Thu, 30 Jan 2020 19:31:16 +0300 Subject: [PATCH 10/85] Bump base image to new Django 3 Besides there are small changes in ansible and all other packages from Alpine and Python 3. --- Dockerfile | 2 +- Makefile | 2 +- requirements.txt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index c27ed1bc47..186bc08092 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM arenadata/adcmbase:20200121195750 +FROM arenadata/adcmbase:20200130192319 COPY . /adcm/ diff --git a/Makefile b/Makefile index c1d6fe481c..ad94a63676 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # Set number of threads BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD) ADCMBASE_IMAGE ?= arenadata/adcmbase -ADCMBASE_TAG ?= 20200121195750 +ADCMBASE_TAG ?= 20200130192319 # Default target diff --git a/requirements.txt b/requirements.txt index 3c4b8f5e7f..a67ccc6b4c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ # ansible==2.8.3 -git+https://github.com/arenadata/ansible.git@v2.8.7-p1 +git+https://github.com/arenadata/ansible.git@v2.8.8-p1 coreapi -django < 3.0 +django django-cors-headers django-filter django-rest-swagger From 820f101306c6f586c0e102c5597621686b22732f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 31 Jan 2020 02:27:27 +0000 Subject: [PATCH 11/85] Bump @types/node from 13.1.8 to 13.5.3 in /web Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 13.1.8 to 13.5.3. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) Signed-off-by: dependabot-preview[bot] --- web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/package.json b/web/package.json index 7135b677a9..1674082ad1 100644 --- a/web/package.json +++ b/web/package.json @@ -39,7 +39,7 @@ "@ngrx/schematics": "^8.6.0", "@types/jasmine": "~3.5.0", "@types/jasminewd2": "~2.0.8", - "@types/node": "~13.1.5", + "@types/node": "~13.5.3", "codelyzer": "^5.2.1", "eslint": "^6.8.0", "jasmine-core": "~3.5.0", From ce6db1ae92fb3aa230a15dd43cb6bf3a14686f76 Mon Sep 17 00:00:00 2001 From: Alexandr Alferov Date: Fri, 31 Jan 2020 12:46:54 +0300 Subject: [PATCH 12/85] ADCM-1098 Added fake update database in finish_task. --- cm/job.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cm/job.py b/cm/job.py index 6a09c00b56..b9624e17f1 100644 --- a/cm/job.py +++ b/cm/job.py @@ -31,7 +31,7 @@ from cm.logger import log from cm.models import ( Cluster, Action, SubAction, TaskLog, JobLog, CheckLog, Host, ADCM, - ClusterObject, HostComponent, ServiceComponent, HostProvider, + ClusterObject, HostComponent, ServiceComponent, HostProvider, DummyData, ) @@ -715,6 +715,7 @@ def finish_task(task, job, status): obj = get_task_obj(action.prototype.type, task.object_id) state = get_state(action, job, status) with transaction.atomic(): + DummyData.objects.filter(id=1).update(date=timezone.now()) if state is not None: set_action_state(action, task, obj, state) unlock_objects(obj) From 08f95f2337caa003a77eda281583bdc7a18c2ef8 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Fri, 31 Jan 2020 14:59:46 +0300 Subject: [PATCH 13/85] ADCM-1106 yspec service for config --- web/src/app/core/types/func.ts | 11 ++- .../shared/configuration/YspecStructure.ts | 22 +++-- .../configuration/configuration.module.ts | 3 +- .../configuration/field.service.spec.ts | 3 +- .../app/shared/configuration/field.service.ts | 18 +++- .../configuration/yspec/yspec.service.spec.ts | 44 +++++++++ .../configuration/yspec/yspec.service.ts | 95 +++++++++++++++++++ 7 files changed, 178 insertions(+), 18 deletions(-) create mode 100644 web/src/app/shared/configuration/yspec/yspec.service.spec.ts create mode 100644 web/src/app/shared/configuration/yspec/yspec.service.ts diff --git a/web/src/app/core/types/func.ts b/web/src/app/core/types/func.ts index eb92478337..dcc58687f3 100644 --- a/web/src/app/core/types/func.ts +++ b/web/src/app/core/types/func.ts @@ -9,8 +9,11 @@ // 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. +import { controlType } from '@app/shared/configuration/field.service'; +import { ConfigResultTypes, ConfigValueTypes, FieldStack } from '@app/shared/configuration/types'; +import { matchType } from '@app/shared/configuration/YspecStructure'; + import { InnerIssue, Issue } from './issue'; -import { FieldStack, ConfigValueTypes, ConfigResultTypes } from '@app/shared/configuration/types'; export function getPattern(name: string): RegExp { const fn = { @@ -21,8 +24,8 @@ export function getPattern(name: string): RegExp { return fn[name] ? fn[name]() : null; } -export function controlType(name: string): string { - const ControlsTypes = { +export function getControlType(name: matchType): controlType { + const a: Partial<{[key in matchType]: controlType}> = { bool: 'boolean', int: 'textbox', integer: 'textbox', @@ -31,7 +34,7 @@ export function controlType(name: string): string { file: 'textarea', text: 'textarea' }; - return ControlsTypes[name] || name; + return a[name]; } export function getTypeName(name: string) { diff --git a/web/src/app/shared/configuration/YspecStructure.ts b/web/src/app/shared/configuration/YspecStructure.ts index 23e5cf2fcf..655c3e99c9 100644 --- a/web/src/app/shared/configuration/YspecStructure.ts +++ b/web/src/app/shared/configuration/YspecStructure.ts @@ -9,13 +9,13 @@ // 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. -import { controlType, getPattern } from '@app/core/types'; +import { getControlType, getPattern } from '@app/core/types'; import { FieldOptions, PanelOptions, ConfigValueTypes } from './types'; -type simpleType = 'string' | 'integer' | 'float' | 'bool'; -type reqursionType = 'list' | 'dict'; -type matchType = simpleType | reqursionType; +export type simpleType = 'string' | 'integer' | 'float' | 'bool' | 'int' | 'file' | 'text' | 'one_of' | 'dict_key_selection'; +export type reqursionType = 'list' | 'dict'; +export type matchType = simpleType | reqursionType; interface Iroot { match: matchType; @@ -39,7 +39,7 @@ class Field { name: this.key, key: this.key, subname: null, - controlType: controlType(this.value), + controlType: getControlType(this.value), type: this.value as ConfigValueTypes, validator: { required: true, @@ -53,6 +53,10 @@ class Field { get options() { return this._options; } + setSubname(name: string) { + this._options.subname = name; + return this; + } setKey(key: string) { this._options.key = `${this.key}/${key}`; return this; @@ -69,6 +73,10 @@ class Group { options(value: simpleType) { return {}; } + setSubname(name: string) { + //this._options.subname = name; + return this; + } setValue(value: simpleType) { // this.options.default = value; // this.options.value = value; @@ -118,7 +126,7 @@ export class YspecStructure { if (typeof v === 'object') { return { display_name: `--- ${i} ---`, - name: i, + name: i.toString(), key: `${i}/${source.key}`, type: 'group', options: Object.keys(v).map( @@ -163,7 +171,7 @@ export class YspecStructure { value: value[k], hidden: false, read_only: false, - controlType: controlType(rule.match), + controlType: getControlType(rule.match), type: rule.match, validator: { required: !!(root.required_items && root.required_items.includes[k]), diff --git a/web/src/app/shared/configuration/configuration.module.ts b/web/src/app/shared/configuration/configuration.module.ts index a40ed3e303..3815fb475c 100644 --- a/web/src/app/shared/configuration/configuration.module.ts +++ b/web/src/app/shared/configuration/configuration.module.ts @@ -25,6 +25,7 @@ import { ColorOptionDirective } from './tools/color-option.directive'; import { HistoryComponent } from './tools/history.component'; import { SearchComponent } from './tools/search.component'; import { ToolsComponent } from './tools/tools.component'; +import { YspecService } from './yspec/yspec.service'; @NgModule({ declarations: [ @@ -39,6 +40,6 @@ import { ToolsComponent } from './tools/tools.component'; ], imports: [CommonModule, FormsModule, ReactiveFormsModule, MaterialModule, StuffModule, FormElementsModule], exports: [ConfigComponent, ConfigFieldsComponent], - providers: [FieldService] + providers: [FieldService, YspecService] }) export class ConfigurationModule {} diff --git a/web/src/app/shared/configuration/field.service.spec.ts b/web/src/app/shared/configuration/field.service.spec.ts index 027ee8ae1f..7cb14bbd76 100644 --- a/web/src/app/shared/configuration/field.service.spec.ts +++ b/web/src/app/shared/configuration/field.service.spec.ts @@ -13,13 +13,14 @@ import { TestBed } from '@angular/core/testing'; import { FieldService } from './field.service'; import { FormBuilder } from '@angular/forms'; +import { YspecService } from './yspec/yspec.service'; describe('Configuration fields service', () => { let service: FieldService; beforeEach(() => { TestBed.configureTestingModule({ - providers: [FormBuilder, FieldService] + providers: [FormBuilder, FieldService, YspecService] }); service = TestBed.get(FieldService); diff --git a/web/src/app/shared/configuration/field.service.ts b/web/src/app/shared/configuration/field.service.ts index 6ca30b07cf..8cb452e3fe 100644 --- a/web/src/app/shared/configuration/field.service.ts +++ b/web/src/app/shared/configuration/field.service.ts @@ -11,16 +11,19 @@ // limitations under the License. import { Injectable } from '@angular/core'; import { AbstractControl, FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms'; -import { controlType, getPattern, isObject } from '@app/core/types'; +import { getControlType, getPattern, isObject } from '@app/core/types'; import { ConfigOptions, ConfigResultTypes, ConfigValueTypes, FieldOptions, FieldStack, IConfig, PanelOptions } from './types'; -import { YspecStructure } from './YspecStructure'; +import { YspecStructure, matchType } from './YspecStructure'; +import { YspecService } from './yspec/yspec.service'; export interface IToolsEvent { name: string; conditions?: { advanced: boolean; search: string } | boolean; } +export type controlType = 'boolean' | 'textbox' | 'textarea' | 'json' | 'password' | 'list' | 'map' | 'dropdown'; + @Injectable() export class FieldService { globalConfig: IConfig; @@ -28,7 +31,7 @@ export class FieldService { formOptions: FieldOptions[]; form = new FormGroup({}); - constructor(private fb: FormBuilder) {} + constructor(private fb: FormBuilder, private spec: YspecService) {} isVisibleField = (a: ConfigOptions) => !a.ui_options || !a.ui_options.invisible; isInvisibleField = (a: ConfigOptions) => a.ui_options && a.ui_options.invisible; @@ -60,6 +63,10 @@ export class FieldService { a.name = a.subname || a.name; if (a.limits && a.limits.yspec) { + + this.spec.Root = a.limits.yspec; + const output = this.spec.build(); + const yspec = new YspecStructure(a); return yspec.output; } @@ -78,7 +85,7 @@ export class FieldService { max: item.limits ? item.limits.max : null, pattern: getPattern(item.type) }, - controlType: controlType(item.type), + controlType: getControlType(item.type as matchType), hidden: item.name === '__main_info' || this.isHidden(item), compare: [] }; @@ -182,7 +189,8 @@ export class FieldService { }, json: (value: string) => (value === null ? '' : JSON.stringify(value, undefined, 4)), map: (value: object, de: object) => (!value ? (!de ? {} : de) : value), - list: (value: string[], de: string[]) => (!value ? (!de ? [] : de) : value) + list: (value: string[], de: string[]) => (!value ? (!de ? [] : de) : value), + structure: (value: any) => value }; return data[name] ? data[name] : def; diff --git a/web/src/app/shared/configuration/yspec/yspec.service.spec.ts b/web/src/app/shared/configuration/yspec/yspec.service.spec.ts new file mode 100644 index 0000000000..b9831b80ea --- /dev/null +++ b/web/src/app/shared/configuration/yspec/yspec.service.spec.ts @@ -0,0 +1,44 @@ +// 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.s +import { YspecService, IField } from './yspec.service'; + +const mockField: IField = { + name: 'root', + type: 'string', + controlType: 'textbox', + validator: { + required: false, + pattern: null + } +}; + +describe('YspecService', () => { + let service: YspecService; + + beforeEach(() => { + service = new YspecService(); + service.Root = { root: { match: 'list', item: 'string' } }; + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); + + it('create Root element', () => { + expect(service.Root.root).toBeDefined(); + expect(service.Root.root.match).toBeDefined(); + }); + + it('create Field instance', () => { + expect(service.createField({ path: ['root'], type: 'string' })).toEqual(mockField); + }); +}); diff --git a/web/src/app/shared/configuration/yspec/yspec.service.ts b/web/src/app/shared/configuration/yspec/yspec.service.ts new file mode 100644 index 0000000000..4f5975c8c4 --- /dev/null +++ b/web/src/app/shared/configuration/yspec/yspec.service.ts @@ -0,0 +1,95 @@ +// 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. +import { getControlType, IRoot, getPattern } from '@app/core/types'; + +import { controlType } from '../field.service'; +import { IYspec, simpleType } from '../YspecStructure'; +import { pathToFileURL } from 'url'; + +export interface IField { + name: string; + type: simpleType; + controlType: controlType; + validator: { + required: boolean; + pattern: RegExp | null; + }; +} + +export class YspecService { + private root: IYspec; + private output: any; + + constructor() {} + + set Root(yspec: IYspec) { + this.root = yspec; + } + + get Root() { + return this.root; + } + + build(rule = 'root', path: string[] = []) { + const { match, item, items } = { ...this.Root[rule] }; + + switch (match) { + case 'list': { + if (this.Root[item]) { + return this.build(item, [...path, item]); + } + break; + } + case 'dict': { + return Object.keys(items).map((item_name: string) => { + return this.build(items[item_name], [...path, item_name]); + }); + break; + } + // case 'one_of': + // return this.one_of(); + // case 'dict_key_selection': + // return this.dict_key_selection(); + default: + return this.createField({ type: match, path }); + } + } + + createField(field: { path: string[]; type: simpleType }): IField { + const [name, ...o] = [...field.path].reverse(); + return { + name, + type: field.type, + controlType: getControlType(field.type), + validator: { + required: this.findRule(field.path, 'required_items'), + pattern: getPattern(field.type) + } + }; + } + + findRule(path: string[], name: string): boolean { + const [field, ...other] = [...path].reverse(); + const rule = this.Root[other[0]]; + return !!(rule && rule[name] && rule[name][field]); + } + + list(item: string) {} + + dict(items: IRoot) {} + + simple(match: simpleType) {} + + one_of() {} + + dict_key_selection() {} +} From 3aedaeb58c523e7e0621ea35cffaa66b6b605112 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Mon, 3 Feb 2020 11:31:26 +0300 Subject: [PATCH 14/85] ADCM-1076 moved scroll controls on the job page --- web/src/app/entry/job/log.component.ts | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/web/src/app/entry/job/log.component.ts b/web/src/app/entry/job/log.component.ts index 9901b677b6..5973b21a77 100644 --- a/web/src/app/entry/job/log.component.ts +++ b/web/src/app/entry/job/log.component.ts @@ -23,21 +23,21 @@ import { JobInfoComponent } from './job-info.component'; @Component({ selector: 'app-job-log', template: ` -
- - - - -
- -
- + +
+ + + + +
+ +
@@ -57,7 +57,7 @@ import { JobInfoComponent } from './job-info.component'; `, styles: [ ':host {display: flex; flex: 1; flex-direction: column;}', - '.tools { position: fixed; right: 80px; }', + '.tools { position: fixed; right: 60px; top: 150px; }', 'div.wrap {display: flex; flex: 1; flex-direction: column;padding: 10px;}', 'textarea.log, textarea.check {background-color: #424242; border: 0; color: #fff;flex: 1;}', 'textarea.check {height: 300px;width: 100%;}', From 038e341dd957ff507a0f9ec16772f249e6fb2d98 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Mon, 3 Feb 2020 16:28:35 +0300 Subject: [PATCH 15/85] ADCM-1106 fixed the displaying fields not standard --- web/src/app/core/types/func.ts | 6 +++--- web/src/app/shared/configuration/YspecStructure.ts | 2 +- web/src/app/shared/configuration/field.service.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/src/app/core/types/func.ts b/web/src/app/core/types/func.ts index dcc58687f3..7421ce8c1c 100644 --- a/web/src/app/core/types/func.ts +++ b/web/src/app/core/types/func.ts @@ -24,8 +24,8 @@ export function getPattern(name: string): RegExp { return fn[name] ? fn[name]() : null; } -export function getControlType(name: matchType): controlType { - const a: Partial<{[key in matchType]: controlType}> = { +export function getControlType(name: string): controlType { + const a: Partial<{[key in matchType | controlType]: controlType}> = { bool: 'boolean', int: 'textbox', integer: 'textbox', @@ -34,7 +34,7 @@ export function getControlType(name: matchType): controlType { file: 'textarea', text: 'textarea' }; - return a[name]; + return a[name] || name; } export function getTypeName(name: string) { diff --git a/web/src/app/shared/configuration/YspecStructure.ts b/web/src/app/shared/configuration/YspecStructure.ts index 655c3e99c9..cc44ba032e 100644 --- a/web/src/app/shared/configuration/YspecStructure.ts +++ b/web/src/app/shared/configuration/YspecStructure.ts @@ -13,7 +13,7 @@ import { getControlType, getPattern } from '@app/core/types'; import { FieldOptions, PanelOptions, ConfigValueTypes } from './types'; -export type simpleType = 'string' | 'integer' | 'float' | 'bool' | 'int' | 'file' | 'text' | 'one_of' | 'dict_key_selection'; +export type simpleType = 'string' | 'integer' | 'float' | 'bool' | 'int' | 'one_of' | 'dict_key_selection'; export type reqursionType = 'list' | 'dict'; export type matchType = simpleType | reqursionType; diff --git a/web/src/app/shared/configuration/field.service.ts b/web/src/app/shared/configuration/field.service.ts index 8cb452e3fe..1162c5ab4b 100644 --- a/web/src/app/shared/configuration/field.service.ts +++ b/web/src/app/shared/configuration/field.service.ts @@ -22,7 +22,7 @@ export interface IToolsEvent { conditions?: { advanced: boolean; search: string } | boolean; } -export type controlType = 'boolean' | 'textbox' | 'textarea' | 'json' | 'password' | 'list' | 'map' | 'dropdown'; +export type controlType = 'boolean' | 'textbox' | 'textarea' | 'json' | 'password' | 'list' | 'map' | 'dropdown' | 'file' | 'text'; @Injectable() export class FieldService { From 1b886ba37b9f480282c535c956fc5941879a2e34 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Mon, 3 Feb 2020 16:37:04 +0300 Subject: [PATCH 16/85] ADCM-1050 removed 'disabled' attr from config fields --- web/src/app/shared/configuration/field.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/app/shared/configuration/field.service.ts b/web/src/app/shared/configuration/field.service.ts index 6ca30b07cf..85f312245c 100644 --- a/web/src/app/shared/configuration/field.service.ts +++ b/web/src/app/shared/configuration/field.service.ts @@ -145,10 +145,10 @@ export class FieldService { fillForm(field: FieldOptions, controls: {}) { const name = field.subname || field.name; - controls[name] = this.fb.control({ value: field.value, disabled: field.disabled }, this.setValidator(field)); + controls[name] = this.fb.control(field.value, this.setValidator(field)); if (field.controlType === 'password') { if (!field.ui_options || (field.ui_options && !field.ui_options.no_confirm)) { - controls[`confirm_${name}`] = this.fb.control({ value: field.value, disabled: field.disabled }, this.setValidator(field)); + controls[`confirm_${name}`] = this.fb.control(field.value, this.setValidator(field)); } } return controls; From 3e581172bc55c2a2c678dbd43b34ed1f69597cbc Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Mon, 3 Feb 2020 17:18:30 +0300 Subject: [PATCH 17/85] ADCM-1118 fixed field validation for external group --- .../group-fields/group-fields.component.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/web/src/app/shared/configuration/group-fields/group-fields.component.ts b/web/src/app/shared/configuration/group-fields/group-fields.component.ts index 0b2f588542..1814d9076a 100644 --- a/web/src/app/shared/configuration/group-fields/group-fields.component.ts +++ b/web/src/app/shared/configuration/group-fields/group-fields.component.ts @@ -60,17 +60,13 @@ export class GroupFieldsComponent implements OnInit { .filter(a => !('options' in a)) .forEach((a: FieldOptions) => { const split = a.key.split('/'); - let formControl = (this.form.controls[split[1]] as FormGroup).controls[split[0]]; - if (split.length > 2) { - const [name, ...other] = split; - const currentFormGroup = other.reverse().reduce((p, c) => p.get(c), this.form) as FormGroup; - formControl = currentFormGroup.controls[name]; - } + + const [name, ...other] = split; + const currentFormGroup = other.reverse().reduce((p, c) => p.get(c), this.form) as FormGroup; + const formControl = currentFormGroup.controls[name]; this.updateValidator(formControl, a, flag); - if (a.type === 'password') { - this.updateValidator(this.form.controls['confirm_' + name], a, flag); - } + if (a.type === 'password') this.updateValidator(currentFormGroup.controls['confirm_' + name], a, flag); }); } From f3286b3589a3e55f612a9ce8e554c7e7d3da957f Mon Sep 17 00:00:00 2001 From: Alexandr Alferov Date: Mon, 3 Feb 2020 17:27:13 +0300 Subject: [PATCH 18/85] ADCM-1113 Corrected argument "export" on "export.prototype" for function proto_ref. --- cm/upgrade.py | 51 ++++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/cm/upgrade.py b/cm/upgrade.py index a2a3d80ec9..af9313a3bf 100644 --- a/cm/upgrade.py +++ b/cm/upgrade.py @@ -10,17 +10,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -import json import functools +import json -from version_utils import rpm from django.db import transaction +from version_utils import rpm -import cm.status_api +import cm.issue import cm.config as config -from cm.logger import log # pylint: disable=unused-import +import cm.status_api from cm.adcm_config import proto_ref, obj_ref, switch_config from cm.errors import raise_AdcmEx as err +from cm.logger import log # pylint: disable=unused-import from cm.models import Prototype, Component, Host, HostComponent, ServiceComponent from cm.models import PrototypeImport, ClusterBind, ClusterObject, Upgrade @@ -78,46 +79,46 @@ def check_upgrade_version(obj, upgrade): if upgrade.min_strict: if rpm.compare_versions(proto.version, upgrade.min_version) <= 0: msg = '{} version {} is less than or equal to upgrade min version {}' - return (False, msg.format(proto.type, proto.version, upgrade.min_version)) + return False, msg.format(proto.type, proto.version, upgrade.min_version) else: if rpm.compare_versions(proto.version, upgrade.min_version) < 0: msg = '{} version {} is less than upgrade min version {}' - return (False, msg.format(proto.type, proto.version, upgrade.min_version)) + return False, msg.format(proto.type, proto.version, upgrade.min_version) if upgrade.max_strict: if rpm.compare_versions(proto.version, upgrade.max_version) >= 0: msg = '{} version {} is more than or equal to upgrade max version {}' - return (False, msg.format(proto.type, proto.version, upgrade.max_version)) + return False, msg.format(proto.type, proto.version, upgrade.max_version) else: if rpm.compare_versions(proto.version, upgrade.max_version) > 0: msg = '{} version {} is more than upgrade max version {}' - return (False, msg.format(proto.type, proto.version, upgrade.max_version)) - return (True, '') + return False, msg.format(proto.type, proto.version, upgrade.max_version) + return True, '' def check_upgrade_edition(obj, upgrade): if not upgrade.from_edition: - return (True, '') + return True, '' from_edition = json.loads(upgrade.from_edition) if obj.prototype.bundle.edition not in from_edition: msg = 'bundle edition "{}" is not in upgrade list: {}' - return (False, msg.format(obj.prototype.bundle.edition, from_edition)) - return (True, '') + return False, msg.format(obj.prototype.bundle.edition, from_edition) + return True, '' def check_upgrade_state(obj, upgrade): if obj.state == config.Job.LOCKED: - return (False, 'object is locked') + return False, 'object is locked' if upgrade.state_available: available = json.loads(upgrade.state_available) if obj.state in available: - return (True, '') + return True, '' elif available == 'any': - return (True, '') + return True, '' else: msg = '{} state "{}" is not in available states list: {}' - return (False, msg.format(obj.prototype.type, obj.state, available)) + return False, msg.format(obj.prototype.type, obj.state, available) else: - return (False, 'no available states') + return False, 'no available states' def check_upgrade_import(obj, upgrade): # pylint: disable=too-many-branches @@ -134,7 +135,7 @@ def get_import(cbind): # pylint: disable=redefined-outer-name return cbind.cluster if obj.prototype.type != 'cluster': - return (True, '') + return True, '' for cbind in ClusterBind.objects.filter(cluster=obj): export = get_export(cbind) @@ -145,12 +146,12 @@ def get_import(cbind): # pylint: disable=redefined-outer-name ) except Prototype.DoesNotExist: msg = 'Upgrade does not have new version of {} required for import' - return (False, msg.format(proto_ref(impr_obj.prototype))) + return False, msg.format(proto_ref(impr_obj.prototype)) try: pi = PrototypeImport.objects.get(prototype=proto, name=export.prototype.name) except PrototypeImport.DoesNotExist: msg = 'New version of {} does not have import "{}"' - return (False, msg.format(proto_ref(proto), export.prototype.name)) + return False, msg.format(proto_ref(proto), export.prototype.name) if not version_in(export.prototype.version, pi): msg = 'Import "{}" of {} versions ({}, {}) does not match export version: {} ({})' return (False, msg.format( @@ -166,7 +167,7 @@ def get_import(cbind): # pylint: disable=redefined-outer-name ) except Prototype.DoesNotExist: msg = 'Upgrade does not have new version of {} required for export' - return (False, msg.format(proto_ref(export))) + return False, msg.format(proto_ref(export.prototype)) import_obj = get_import(cbind) pi = PrototypeImport.objects.get(prototype=import_obj.prototype, name=export.prototype.name) if not version_in(proto.version, pi): @@ -175,13 +176,13 @@ def get_import(cbind): # pylint: disable=redefined-outer-name proto_ref(proto), pi.min_version, pi.max_version, obj_ref(import_obj) )) - return (True, '') + return True, '' def check_upgrade(obj, upgrade): issue = cm.issue.get_issue(obj) if not cm.issue.issue_to_bool(issue): - return (False, '{} has issue: {}'.format(obj_ref(obj), issue)) + return False, '{} has issue: {}'.format(obj_ref(obj), issue) check_list = [ check_upgrade_version, check_upgrade_edition, check_upgrade_state, check_upgrade_import @@ -189,8 +190,8 @@ def check_upgrade(obj, upgrade): for func in check_list: ok, msg = func(obj, upgrade) if not ok: - return (False, msg) - return (True, '') + return False, msg + return True, '' def switch_hc(obj, upgrade): From f413d5a3ca50301014bb705bbc4ba9108445ee71 Mon Sep 17 00:00:00 2001 From: Anton Chevychalov Date: Mon, 3 Feb 2020 17:56:15 +0300 Subject: [PATCH 19/85] ADCM-270 Unfreeze markdown in requirements.txt Upstream issue https://github.com/encode/django-rest-framework/issues/6203 was fixed so I think we can remove that restriction. --- Dockerfile | 2 +- Makefile | 2 +- requirements.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 186bc08092..484472d5b0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM arenadata/adcmbase:20200130192319 +FROM arenadata/adcmbase:20200203174702 COPY . /adcm/ diff --git a/Makefile b/Makefile index ad94a63676..e1aa66d2dc 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # Set number of threads BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD) ADCMBASE_IMAGE ?= arenadata/adcmbase -ADCMBASE_TAG ?= 20200130192319 +ADCMBASE_TAG ?= 20200203174702 # Default target diff --git a/requirements.txt b/requirements.txt index a67ccc6b4c..2e504f9b3e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,7 +9,7 @@ djangorestframework social-auth-app-django git+git://github.com/arenadata/django-generate-secret-key.git jinja2 -markdown==2.6.11 # Due to bug in djangorestframework +markdown pyyaml toml uwsgi From 05ccce097341547d8e1361d4ed4060efe56e6545 Mon Sep 17 00:00:00 2001 From: Konstantin Voschanov Date: Mon, 3 Feb 2020 18:11:09 +0300 Subject: [PATCH 20/85] fix docs template to Django 3.0 --- api/templates/docs-md/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/templates/docs-md/index.md b/api/templates/docs-md/index.md index 80d4d478ef..6c5c397ce5 100644 --- a/api/templates/docs-md/index.md +++ b/api/templates/docs-md/index.md @@ -1,3 +1,3 @@ -{% load staticfiles %} +{% load static %} {% include "docs-md/document.md" %} From c8091f397af9c4f1be74a261c333cf49c255a5a9 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Mon, 3 Feb 2020 18:21:14 +0300 Subject: [PATCH 21/85] ADCM-1106 has added tests --- .../configuration/yspec/yspec.service.spec.ts | 65 ++++++++++++++++++- .../configuration/yspec/yspec.service.ts | 5 +- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/web/src/app/shared/configuration/yspec/yspec.service.spec.ts b/web/src/app/shared/configuration/yspec/yspec.service.spec.ts index b9831b80ea..e76666e5cb 100644 --- a/web/src/app/shared/configuration/yspec/yspec.service.spec.ts +++ b/web/src/app/shared/configuration/yspec/yspec.service.spec.ts @@ -10,23 +10,32 @@ // See the License for the specific language governing permissions and // limitations under the License.s import { YspecService, IField } from './yspec.service'; +import { IYspec } from '../YspecStructure'; +import { getPattern } from '@app/core/types'; -const mockField: IField = { +const simpleField: IField = { name: 'root', type: 'string', controlType: 'textbox', + path: ['root'], validator: { required: false, pattern: null } }; +const simpleStr: IYspec = { + root: { match: 'list', item: 'simpl_str' }, + simpl_str: { + match: 'string' + } +}; + describe('YspecService', () => { let service: YspecService; beforeEach(() => { service = new YspecService(); - service.Root = { root: { match: 'list', item: 'string' } }; }); it('should be created', () => { @@ -34,11 +43,61 @@ describe('YspecService', () => { }); it('create Root element', () => { + service.Root = simpleStr; expect(service.Root.root).toBeDefined(); expect(service.Root.root.match).toBeDefined(); }); it('create Field instance', () => { - expect(service.createField({ path: ['root'], type: 'string' })).toEqual(mockField); + service.Root = simpleStr; + expect(service.createField({ path: ['root'], type: 'string' })).toEqual(simpleField); + }); + + xit('create List', () => { + service.Root = { + root: { match: 'list', item: 'country_code' }, + country_code: { + match: 'dict', + items: { + country: 'str', + code: 'int' + } + }, + str: { + match: 'string' + }, + int: { + match: 'integer' + } + }; + + const output = [ + { + country: { + name: 'country', + type: 'string', + controlType: 'textbox', + path: ['country_code', 'country'], + validator: { + required: false, + pattern: null + } + } + }, + { + code: { + name: 'code', + type: 'integer', + controlType: 'textbox', + path: ['country_code', 'code'], + validator: { + required: false, + pattern: getPattern('integer') + } + } + } + ]; + + expect(service.build()).toEqual(output); }); }); diff --git a/web/src/app/shared/configuration/yspec/yspec.service.ts b/web/src/app/shared/configuration/yspec/yspec.service.ts index 4f5975c8c4..dd517b75a4 100644 --- a/web/src/app/shared/configuration/yspec/yspec.service.ts +++ b/web/src/app/shared/configuration/yspec/yspec.service.ts @@ -9,15 +9,15 @@ // 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. -import { getControlType, IRoot, getPattern } from '@app/core/types'; +import { getControlType, getPattern, IRoot } from '@app/core/types'; import { controlType } from '../field.service'; import { IYspec, simpleType } from '../YspecStructure'; -import { pathToFileURL } from 'url'; export interface IField { name: string; type: simpleType; + path: string[]; controlType: controlType; validator: { required: boolean; @@ -69,6 +69,7 @@ export class YspecService { return { name, type: field.type, + path: field.path, controlType: getControlType(field.type), validator: { required: this.findRule(field.path, 'required_items'), From 77c154ac1169db2350dcfb36430c4337e5fdcf6c Mon Sep 17 00:00:00 2001 From: Konstantin Voschanov Date: Mon, 3 Feb 2020 19:13:28 +0300 Subject: [PATCH 22/85] restore test bundles --- data/download/adb.2.6.tar | Bin 0 -> 18944 bytes data/download/ssh.1.3.tar | Bin 0 -> 10240 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 data/download/adb.2.6.tar create mode 100644 data/download/ssh.1.3.tar diff --git a/data/download/adb.2.6.tar b/data/download/adb.2.6.tar new file mode 100644 index 0000000000000000000000000000000000000000..eb35425f1b01b0b2786234cb2c961ae7d579d85a GIT binary patch literal 18944 zcmeHOOK;mo5cW0v6$CFiRHjJrp+JBSZsRsa13O66AdMjyw6v00QzAoBZd}9vy)*mb zTapt=c3ScviTjwHnVp^ac6OzA4|e_-hS7H%^#H$J_HFcR`VK|(QBBKn>|Wn84O2Bt zvv1f3sV1Q+kdNHte6Z=Ve*E}LLn@*dnQ8;*nQ0j`7&#FrAjss8uiFarRpqI_& z-!l3Zoqx-6op%2BVJLbxA@Qw0Cduv$VB`5WT*ozCSpSw|o9+DXdHz%HtG^Q?*m(ZY z|M$@U+jie==YP-h|4$h1Wcq2`-zfeYu50%CIRBR2&i_89{~+i8asJ2QV(QQIJ8vFr zZ+KY$uFddX9saXy!)EwT&cEvz#(`>VkA-GR|8xAe@aANoem+0{{p94`$$KTei{PDO z0%byyaqLH_A1D!GJWDn^Nm-Xn)C=@fL}H6_84!aB(^H`~aw? zVMKoxnly75MumnbKm&tev{n9us_3`m0rZfPl6t*ckjw+A2kON*CeUEg5tBtl9m(!U z3{;UU$AAlyfoMf0>hcsH!txw4TA}ZQT5*VCg~o(e$zE| zBZH^XM!OL-@Mgu?<7L3?1sK8&wbPs9wZm z9;PItCFuy<++cXDU4y}`n;@=IoFb}B{J|$JK%OR09+pBN))eJ}<2;>5r;+jk z*AX^Iz~hj`m}tsHxs?vCckV4F$!Mf1FQgx)g9+Hlov=phu`$-3o_!b|zkR!!WFtl9 zjy38aI0prynKT$Ja-wi-2)smrcXtJ@iwX#hC~$*v85^PELSy(q8@{m7Pd88Uq+mIGaV<)qh zoB)*&hU=ihF~+YPb1bd^Zz77JDrhLK6Bj${tP9Z4Fl1@a0fHNQN$?FK7*oE0F?tz! zjFh~+#>>SeVB|##?wl?^ZfEtjOJ!=LELX4&3-bMt3wos0uau^d8Z-&F_R ztS@&Y)$Z%YMpOp9o^q|#sD=U7k#Zd-=`0SH5n7kDhKgMU!_3Xbrx)7zk9 zCPX&)FXv~!p8i&yqQcl;{wCav*HPWs%#8yd78UFjS9{4H22+;s9}Qeo$6JIRYw(|G z+D-}oxt7~&@!uAwppn$!;h}PvPqe8r+$#_t(Z|64NxQ#?^o=e(&cg!+%9)p5lNfRe zV{EesvBRww^Bp#H5L-Iw;enELRF?vw!T3J7C&*5S05(vim!Y;u12vChM;R`}jU3NZ z9%XbjEEYZ3ozO~)z0q~mj-!tIMU*7+t_di_M zYR`Z7ViC$AqBfBb7w5iM!VX{m_!$m`@l~Gr!jUg65V;M0$iT=HPJ*!;Cf5WE#CI`L z{xlFvWnQA@#0~2i)?x><879OUd{}M6SsR>$mJSzK_P@-696}uI(FK9MA2}f9sOAI~ z%WF+s?2@yFGT%~4(qDi{4=o+lfpdL~pjw8;}Gn_|B15r;x`=SmZL zqQypL2~PC^ko)RI^V`XAc>L*Ltvi{pa-GzQKBXqB-m_t+LFlC&RdNS+V|3?% zc0@t13XLIO9T0DkYd(yZ`~(nN!&P5c4T3b2DA!m6E;SHvFTST8`0RtX|O6KjY`Lkv=|@27ELyY}b#07`kx;9cxR&Y%mllw#@$j zw~NdVlWd*;H*LKC1^@q)|NnCwvpxUYi&+%6vfP@f#k2g+@#~-Io7~3sU>i$IWeJV ze2Uok^XpT%^Jm(lf9KHN42SP%LpY_B`3Cq)wvnY9kQ5~A*iGMjUL@C}OVV-In_RVt zguSfc?-?ZX|8muQ54qaD>-;~%|KR`O|6jI=_}}SS{TBb%Ds#()E&iu}fMa`&7XPDn ervV5)8nzlO{{JuG|1Gt;<+OpRQmcNp zWl~jwXC(Be#+?=#7F5=oaeu`teVUz4{4So3KDb(oWxl9trZO^@tPz?$4(zIsRjW-T z6Fju9$r~=YiI{R#J=JXJps5Cc!5U%=}nu9^)06bt?GjZ{=V{|TUez4 zn-R)8GO)K)(&h&EkDuTjM}|JrZl?%=Xm8EB(*lNTUQlUS@#O%bWDB~ffu!(D^wot7 zp1fNrwpGbwzhsj5KsEg)q{-_slffaAm!UAO>W;PLANx4 z&7@?eo$UFsSOzQu?~8$7u3E1> literal 0 HcmV?d00001 From fed9daccf81224587df2dccf2b05c4e3c8801f5e Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Mon, 3 Feb 2020 19:17:49 +0300 Subject: [PATCH 23/85] ADCM-1106 structure is ready --- .../app/shared/configuration/yspec/yspec.service.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/web/src/app/shared/configuration/yspec/yspec.service.ts b/web/src/app/shared/configuration/yspec/yspec.service.ts index dd517b75a4..d7fd1cb5c6 100644 --- a/web/src/app/shared/configuration/yspec/yspec.service.ts +++ b/web/src/app/shared/configuration/yspec/yspec.service.ts @@ -45,14 +45,19 @@ export class YspecService { switch (match) { case 'list': { if (this.Root[item]) { - return this.build(item, [...path, item]); + const name = path.reverse()[0] || 'root'; + return { type: 'list', [name]: this.build(item, [...path, item]) }; } break; } case 'dict': { - return Object.keys(items).map((item_name: string) => { - return this.build(items[item_name], [...path, item_name]); - }); + const name = path.reverse()[0] || 'root'; + return { + type: 'dict', + [name]: Object.keys(items).map((item_name: string) => { + return this.build(items[item_name], [...path, item_name]); + }) + }; break; } // case 'one_of': From c5e493cf66c3838acc9d037cbec902ac5353e3ae Mon Sep 17 00:00:00 2001 From: Mikhail Samoylov Date: Mon, 3 Feb 2020 19:40:29 +0300 Subject: [PATCH 24/85] Enable test with missing service config. --- tests/functional/test_upgrade_cluster_imports.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/functional/test_upgrade_cluster_imports.py b/tests/functional/test_upgrade_cluster_imports.py index 3b1dd01be5..a2ba15a7a4 100644 --- a/tests/functional/test_upgrade_cluster_imports.py +++ b/tests/functional/test_upgrade_cluster_imports.py @@ -97,7 +97,6 @@ def test_incorrect_import_version(sdk_client_fs: ADCMClient): err.UPGRADE_ERROR.equal(e) -@pytest.mark.xfail(reason="ADCM-1113") def test_upgrade_cluster_without_service_config_in_import(sdk_client_fs: ADCMClient): """Upgrade cluster with service when in new cluster we haven't some service configuration variables From 68d10f5f647296e7650a91cccc5d8724172450d2 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Tue, 4 Feb 2020 13:08:56 +0300 Subject: [PATCH 25/85] ADCM-1106 has added structure.component --- .../configuration/configuration.module.ts | 4 +- .../app/shared/configuration/field.service.ts | 11 ++-- .../configuration/fields/fields.component.ts | 11 ++-- .../group-fields/group-fields.component.html | 13 +++-- .../scheme/scheme.component.html | 1 + .../scheme/scheme.component.scss | 0 .../scheme/scheme.component.spec.ts | 36 +++++++++++++ .../configuration/scheme/scheme.component.ts | 31 +++++++++++ web/src/app/shared/configuration/types.ts | 4 ++ .../configuration/yspec/yspec.service.spec.ts | 53 ++++++++++--------- .../configuration/yspec/yspec.service.ts | 43 +++++++-------- 11 files changed, 144 insertions(+), 63 deletions(-) create mode 100644 web/src/app/shared/configuration/scheme/scheme.component.html create mode 100644 web/src/app/shared/configuration/scheme/scheme.component.scss create mode 100644 web/src/app/shared/configuration/scheme/scheme.component.spec.ts create mode 100644 web/src/app/shared/configuration/scheme/scheme.component.ts diff --git a/web/src/app/shared/configuration/configuration.module.ts b/web/src/app/shared/configuration/configuration.module.ts index 3815fb475c..24f59199d8 100644 --- a/web/src/app/shared/configuration/configuration.module.ts +++ b/web/src/app/shared/configuration/configuration.module.ts @@ -26,6 +26,7 @@ import { HistoryComponent } from './tools/history.component'; import { SearchComponent } from './tools/search.component'; import { ToolsComponent } from './tools/tools.component'; import { YspecService } from './yspec/yspec.service'; +import { SchemeComponent } from './scheme/scheme.component'; @NgModule({ declarations: [ @@ -36,7 +37,8 @@ import { YspecService } from './yspec/yspec.service'; HistoryComponent, SearchComponent, ColorOptionDirective, - ToolsComponent + ToolsComponent, + SchemeComponent ], imports: [CommonModule, FormsModule, ReactiveFormsModule, MaterialModule, StuffModule, FormElementsModule], exports: [ConfigComponent, ConfigFieldsComponent], diff --git a/web/src/app/shared/configuration/field.service.ts b/web/src/app/shared/configuration/field.service.ts index 1162c5ab4b..60363f2192 100644 --- a/web/src/app/shared/configuration/field.service.ts +++ b/web/src/app/shared/configuration/field.service.ts @@ -13,7 +13,7 @@ import { Injectable } from '@angular/core'; import { AbstractControl, FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms'; import { getControlType, getPattern, isObject } from '@app/core/types'; -import { ConfigOptions, ConfigResultTypes, ConfigValueTypes, FieldOptions, FieldStack, IConfig, PanelOptions } from './types'; +import { ConfigOptions, ConfigResultTypes, ConfigValueTypes, FieldOptions, FieldStack, IConfig, PanelOptions, IStructure } from './types'; import { YspecStructure, matchType } from './YspecStructure'; import { YspecService } from './yspec/yspec.service'; @@ -61,14 +61,11 @@ export class FieldService { checkYspec(a: FieldOptions): FieldOptions | PanelOptions { a.name = a.subname || a.name; - if (a.limits && a.limits.yspec) { - this.spec.Root = a.limits.yspec; - const output = this.spec.build(); - - const yspec = new YspecStructure(a); - return yspec.output; + (a as IStructure).rules = this.spec.build(); + // const yspec = new YspecStructure(a); + // return yspec.output; } return a; } diff --git a/web/src/app/shared/configuration/fields/fields.component.ts b/web/src/app/shared/configuration/fields/fields.component.ts index d2fe238bd2..79e0eb3165 100644 --- a/web/src/app/shared/configuration/fields/fields.component.ts +++ b/web/src/app/shared/configuration/fields/fields.component.ts @@ -21,9 +21,14 @@ import { IConfig, PanelOptions, FieldOptions } from '../types'; selector: 'app-config-fields', template: ` - - - + + + + + + + + ` diff --git a/web/src/app/shared/configuration/group-fields/group-fields.component.html b/web/src/app/shared/configuration/group-fields/group-fields.component.html index 5b2a0e2306..53bf5668c3 100644 --- a/web/src/app/shared/configuration/group-fields/group-fields.component.html +++ b/web/src/app/shared/configuration/group-fields/group-fields.component.html @@ -13,11 +13,16 @@
- - + + - - + + + + + + +
diff --git a/web/src/app/shared/configuration/scheme/scheme.component.html b/web/src/app/shared/configuration/scheme/scheme.component.html new file mode 100644 index 0000000000..8122f83b1d --- /dev/null +++ b/web/src/app/shared/configuration/scheme/scheme.component.html @@ -0,0 +1 @@ +
{{ options | json }}
diff --git a/web/src/app/shared/configuration/scheme/scheme.component.scss b/web/src/app/shared/configuration/scheme/scheme.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/web/src/app/shared/configuration/scheme/scheme.component.spec.ts b/web/src/app/shared/configuration/scheme/scheme.component.spec.ts new file mode 100644 index 0000000000..fdfafdd33d --- /dev/null +++ b/web/src/app/shared/configuration/scheme/scheme.component.spec.ts @@ -0,0 +1,36 @@ +// 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. +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SchemeComponent } from './scheme.component'; + +describe('SchemeComponent', () => { + let component: SchemeComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ SchemeComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SchemeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/web/src/app/shared/configuration/scheme/scheme.component.ts b/web/src/app/shared/configuration/scheme/scheme.component.ts new file mode 100644 index 0000000000..432d10abfc --- /dev/null +++ b/web/src/app/shared/configuration/scheme/scheme.component.ts @@ -0,0 +1,31 @@ +// 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. +import { Component, Input, OnInit } from '@angular/core'; +import { FormGroup } from '@angular/forms'; + +import { FieldOptions } from '../types'; + +@Component({ + selector: 'app-scheme', + templateUrl: './scheme.component.html', + styleUrls: ['./scheme.component.scss'] +}) +export class SchemeComponent implements OnInit { + @Input() form: FormGroup; + @Input() options: FieldOptions; + + constructor() {} + + ngOnInit() { + + } +} diff --git a/web/src/app/shared/configuration/types.ts b/web/src/app/shared/configuration/types.ts index e2c19ea559..6c9379df6b 100644 --- a/web/src/app/shared/configuration/types.ts +++ b/web/src/app/shared/configuration/types.ts @@ -123,3 +123,7 @@ export interface FieldOptions extends ConfigOptions { limits?: ILimits; compare: Compare[]; } + +export interface IStructure extends FieldOptions { + rules: { [x: string]: any; type: string }; +} diff --git a/web/src/app/shared/configuration/yspec/yspec.service.spec.ts b/web/src/app/shared/configuration/yspec/yspec.service.spec.ts index e76666e5cb..f7b7bc468e 100644 --- a/web/src/app/shared/configuration/yspec/yspec.service.spec.ts +++ b/web/src/app/shared/configuration/yspec/yspec.service.spec.ts @@ -8,7 +8,7 @@ // 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.s +// limitations under the License. import { YspecService, IField } from './yspec.service'; import { IYspec } from '../YspecStructure'; import { getPattern } from '@app/core/types'; @@ -50,7 +50,7 @@ describe('YspecService', () => { it('create Field instance', () => { service.Root = simpleStr; - expect(service.createField({ path: ['root'], type: 'string' })).toEqual(simpleField); + expect(service.field({ path: ['root'], type: 'string' })).toEqual(simpleField); }); xit('create List', () => { @@ -71,32 +71,35 @@ describe('YspecService', () => { } }; - const output = [ - { - country: { - name: 'country', - type: 'string', - controlType: 'textbox', - path: ['country_code', 'country'], - validator: { - required: false, - pattern: null + const output = { + type: 'dict', + country_code: [ + { + country: { + name: 'country', + type: 'string', + controlType: 'textbox', + path: ['country_code', 'country'], + validator: { + required: false, + pattern: null + } } - } - }, - { - code: { - name: 'code', - type: 'integer', - controlType: 'textbox', - path: ['country_code', 'code'], - validator: { - required: false, - pattern: getPattern('integer') + }, + { + code: { + name: 'code', + type: 'integer', + controlType: 'textbox', + path: ['country_code', 'code'], + validator: { + required: false, + pattern: getPattern('integer') + } } } - } - ]; + ] + }; expect(service.build()).toEqual(output); }); diff --git a/web/src/app/shared/configuration/yspec/yspec.service.ts b/web/src/app/shared/configuration/yspec/yspec.service.ts index d7fd1cb5c6..d0a3330f5c 100644 --- a/web/src/app/shared/configuration/yspec/yspec.service.ts +++ b/web/src/app/shared/configuration/yspec/yspec.service.ts @@ -43,33 +43,20 @@ export class YspecService { const { match, item, items } = { ...this.Root[rule] }; switch (match) { - case 'list': { - if (this.Root[item]) { - const name = path.reverse()[0] || 'root'; - return { type: 'list', [name]: this.build(item, [...path, item]) }; - } - break; - } - case 'dict': { - const name = path.reverse()[0] || 'root'; - return { - type: 'dict', - [name]: Object.keys(items).map((item_name: string) => { - return this.build(items[item_name], [...path, item_name]); - }) - }; - break; - } + case 'list': + return this.list(item, path); + case 'dict': + return this.dict(items, path); // case 'one_of': // return this.one_of(); // case 'dict_key_selection': // return this.dict_key_selection(); default: - return this.createField({ type: match, path }); + return this.field({ type: match, path }); } } - createField(field: { path: string[]; type: simpleType }): IField { + field(field: { path: string[]; type: simpleType }): IField { const [name, ...o] = [...field.path].reverse(); return { name, @@ -89,11 +76,21 @@ export class YspecService { return !!(rule && rule[name] && rule[name][field]); } - list(item: string) {} - - dict(items: IRoot) {} + list(item: string, path: string[]): { [x: string]: any; type: string } { + if (!this.Root[item]) throw new Error('Not itmem for list'); + const name = path.reverse()[0] || 'root'; + return { type: 'list', [name]: this.build(item, [...path, item]) }; + } - simple(match: simpleType) {} + dict(items: IRoot, path: string[]): { [x: string]: any; type: string } { + const name = path.reverse()[0] || 'root'; + return { + type: 'dict', + [name]: Object.keys(items).map((item_name: string) => { + return this.build(items[item_name], [...path, item_name]); + }) + }; + } one_of() {} From 8021c5c518821f4dd1b7cfd7b8eb3980375d993b Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Tue, 4 Feb 2020 14:53:28 +0300 Subject: [PATCH 26/85] ADCM-786 save list parameters --- .../components/list/base-list.directive.ts | 64 ++++++++++++------- .../shared/components/list/list.service.ts | 53 +++++++-------- 2 files changed, 69 insertions(+), 48 deletions(-) diff --git a/web/src/app/shared/components/list/base-list.directive.ts b/web/src/app/shared/components/list/base-list.directive.ts index c447ddc308..dbc612ceab 100644 --- a/web/src/app/shared/components/list/base-list.directive.ts +++ b/web/src/app/shared/components/list/base-list.directive.ts @@ -10,7 +10,7 @@ // See the License for the specific language governing permissions and // limitations under the License. import { Directive, Host, Input, OnDestroy, OnInit } from '@angular/core'; -import { ParamMap } from '@angular/router'; +import { ParamMap, convertToParamMap } from '@angular/router'; import { EventMessage, SocketState } from '@app/core/store'; import { EmmitRow, Entities, getTypeName, Host as AdcmHost, TypeName, Bundle } from '@app/core/types'; import { Store } from '@ngrx/store'; @@ -20,10 +20,11 @@ import { ListComponent } from '../list/list.component'; import { ListService } from './list.service'; import { filter } from 'rxjs/internal/operators/filter'; import { DialogComponent } from '../dialog.component'; -import { switchMap } from 'rxjs/operators'; +import { switchMap, takeWhile } from 'rxjs/operators'; +import { Observable, of } from 'rxjs'; @Directive({ - selector: '[appBaseList]', + selector: '[appBaseList]' }) export class BaseListDirective extends SocketListener implements OnInit, OnDestroy { row: Entities; @@ -38,26 +39,31 @@ export class BaseListDirective extends SocketListener implements OnInit, OnDestr this.parent.type = this.typeName; this.parent.columns = this.service.initInstance(this.typeName).columns; - const limit = +localStorage.getItem('limit'); - if (!limit) localStorage.setItem('limit', '10'); - this.parent.paginator.pageSize = +localStorage.getItem('limit'); + const limit = +localStorage.getItem('list:limit'); + if (!limit) localStorage.setItem('list:limit', '10'); + this.parent.paginator.pageSize = +localStorage.getItem('list:limit'); this.parent.listItemEvt.pipe(this.takeUntil()).subscribe({ next: (event: EmmitRow) => this.listEvents(event) }); - this.parent.route.paramMap.pipe(this.takeUntil()).subscribe(p => { - if (+p.get('page') === 0) { - this.parent.paginator.firstPage(); - } - const ordering = p.get('ordering'); - if (ordering && !this.parent.sort.active) { - this.parent.sort.direction = ordering[0] === '-' ? 'desc' : 'asc'; - this.parent.sort.active = ordering[0] === '-' ? ordering.substr(1) : ordering; - this.parent.sortParam = ordering; - } + this.parent.route.paramMap + .pipe( + filter(p => this.checkParam(p)), + this.takeUntil() + ) + .subscribe(p => { + if (+p.get('page') === 0) { + this.parent.paginator.firstPage(); + } + const ordering = p.get('ordering'); + if (ordering && !this.parent.sort.active) { + this.parent.sort.direction = ordering[0] === '-' ? 'desc' : 'asc'; + this.parent.sort.active = ordering[0] === '-' ? ordering.substr(1) : ordering; + this.parent.sortParam = ordering; + } - this.listParams = p; - this.refresh(); - }); + this.listParams = p; + this.refresh(); + }); super.startListenSocket(); } @@ -67,6 +73,18 @@ export class BaseListDirective extends SocketListener implements OnInit, OnDestr this.parent.listItemEvt.complete(); } + checkParam(p: ParamMap): boolean { + const listParamStr = localStorage.getItem('list:param'); + if (!p.keys.length && listParamStr) { + const json = JSON.parse(listParamStr); + if (json[this.typeName]) { + this.parent.router.navigate(['./', json[this.typeName]], { relativeTo: this.parent.route }); + return false; + } + } + return true; + } + socketListener(m: EventMessage): void { // if (this.typeName === 'job' && m.object.type === 'job' && m.event === 'change_job_status' && m.object.details.type === 'status') { // if (m.object.details.value === 'created' || m.object.details.value === 'success') this.refresh(); @@ -151,15 +169,15 @@ export class BaseListDirective extends SocketListener implements OnInit, OnDestr data: { title: `Accept license agreement`, text: info.text, - controls: { label: 'Do you accept the license agreement?', buttons: ['Yes', 'No'] }, - }, + controls: { label: 'Do you accept the license agreement?', buttons: ['Yes', 'No'] } + } }) .beforeClosed() .pipe( filter(yes => yes), - switchMap(() => this.service.acceptLicense(`${row.license_url}accept/`)), + switchMap(() => this.service.acceptLicense(`${row.license_url}accept/`)) ) - .subscribe(() => row.license = 'accepted'), + .subscribe(() => (row.license = 'accepted')) ); } diff --git a/web/src/app/shared/components/list/list.service.ts b/web/src/app/shared/components/list/list.service.ts index 3cf78ea4cb..4f94726d38 100644 --- a/web/src/app/shared/components/list/list.service.ts +++ b/web/src/app/shared/components/list/list.service.ts @@ -10,7 +10,7 @@ // See the License for the specific language governing permissions and // limitations under the License. import { Injectable } from '@angular/core'; -import { ParamMap } from '@angular/router'; +import { ParamMap, convertToParamMap } from '@angular/router'; import { ApiService } from '@app/core/api'; import { ClusterService } from '@app/core/services'; import { IAction, Bundle, Cluster, Entities, Host, TypeName } from '@app/core/types'; @@ -18,25 +18,14 @@ import { environment } from '@env/environment'; import { switchMap, tap } from 'rxjs/operators'; const COLUMNS_SET = { - cluster: [ - 'name', - 'prototype_version', - 'description', - 'state', - 'status', - 'actions', - 'import', - 'upgrade', - 'config', - 'controls', - ], + cluster: ['name', 'prototype_version', 'description', 'state', 'status', 'actions', 'import', 'upgrade', 'config', 'controls'], host2cluster: ['fqdn', 'provider_name', 'state', 'status', 'actions', 'config', 'remove'], service2cluster: ['display_name', 'version_no_sort', 'state', 'status', 'import', 'actions', 'config'], host: ['fqdn', 'provider_name', 'host2cluster', 'state', 'status', 'actions', 'config', 'controls'], provider: ['name', 'prototype_version', 'state', 'actions', 'upgrade', 'config', 'controls'], job: ['action', 'objects', 'start_date', 'finish_date', 'status'], task: ['id', 'start_date', 'finish_date', 'status'], - bundle: ['name', 'version', 'edition', 'description', 'controls'], + bundle: ['name', 'version', 'edition', 'description', 'controls'] }; export interface ListInstance { @@ -45,10 +34,9 @@ export interface ListInstance { } @Injectable({ - providedIn: 'root', + providedIn: 'root' }) export class ListService { - current: ListInstance; constructor(private api: ApiService, private detail: ClusterService) {} @@ -59,6 +47,21 @@ export class ListService { } getList(p: ParamMap, typeName: string) { + + const listParamStr = localStorage.getItem('list:param'); + if (p.keys.length) { + const param = p.keys.reduce((a, c) => { + a[c] = p.get(c); + return a; + }, {}); + + if (listParamStr) { + const json = JSON.parse(listParamStr); + json[typeName] = param; + localStorage.setItem('list:param', JSON.stringify(json)); + } else localStorage.setItem('list:param', JSON.stringify({ [typeName]: param })); + } + switch (typeName) { case 'host2cluster': return this.detail.getHosts(p); @@ -88,16 +91,16 @@ export class ListService { // host getClustersForHost(row: Host) { - this.api.root - .pipe(switchMap(root => this.api.get(root.cluster).pipe(tap(clusters => (row.clusters = clusters))))) - .subscribe(); + this.api.root.pipe(switchMap(root => this.api.get(root.cluster).pipe(tap(clusters => (row.clusters = clusters))))).subscribe(); } - addClusterToHost(cluster_id: number, row: Host) { - this.api.post(`${environment.apiRoot}cluster/${cluster_id}/host/`, { host_id: row.id }).subscribe(host => { - row.cluster_id = host.cluster_id; - row.cluster_name = host.cluster; - }); + addClusterToHost(cluster_id: number, row: Host) { + this.api + .post(`${environment.apiRoot}cluster/${cluster_id}/host/`, { host_id: row.id }) + .subscribe(host => { + row.cluster_id = host.cluster_id; + row.cluster_name = host.cluster; + }); } checkItem(item: any) { @@ -109,6 +112,6 @@ export class ListService { } getLicenseInfo(url: string) { - return this.api.get<{text: string}>(url); + return this.api.get<{ text: string }>(url); } } From 5fe9841413df1c71e5ef72aeb41d044f7140c261 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Tue, 4 Feb 2020 14:56:45 +0300 Subject: [PATCH 27/85] ADCM-786 removed unnecessary dependencies --- .../app/shared/components/list/base-list.directive.ts | 11 +++++------ web/src/app/shared/components/list/list.service.ts | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/web/src/app/shared/components/list/base-list.directive.ts b/web/src/app/shared/components/list/base-list.directive.ts index dbc612ceab..b5d949baa5 100644 --- a/web/src/app/shared/components/list/base-list.directive.ts +++ b/web/src/app/shared/components/list/base-list.directive.ts @@ -10,18 +10,17 @@ // See the License for the specific language governing permissions and // limitations under the License. import { Directive, Host, Input, OnDestroy, OnInit } from '@angular/core'; -import { ParamMap, convertToParamMap } from '@angular/router'; +import { ParamMap } from '@angular/router'; import { EventMessage, SocketState } from '@app/core/store'; -import { EmmitRow, Entities, getTypeName, Host as AdcmHost, TypeName, Bundle } from '@app/core/types'; +import { Bundle, EmmitRow, Entities, getTypeName, Host as AdcmHost, TypeName } from '@app/core/types'; import { Store } from '@ngrx/store'; +import { filter } from 'rxjs/internal/operators/filter'; +import { switchMap } from 'rxjs/operators'; import { SocketListener } from '../../directives/base.directive'; +import { DialogComponent } from '../dialog.component'; import { ListComponent } from '../list/list.component'; import { ListService } from './list.service'; -import { filter } from 'rxjs/internal/operators/filter'; -import { DialogComponent } from '../dialog.component'; -import { switchMap, takeWhile } from 'rxjs/operators'; -import { Observable, of } from 'rxjs'; @Directive({ selector: '[appBaseList]' diff --git a/web/src/app/shared/components/list/list.service.ts b/web/src/app/shared/components/list/list.service.ts index 4f94726d38..d7733be61f 100644 --- a/web/src/app/shared/components/list/list.service.ts +++ b/web/src/app/shared/components/list/list.service.ts @@ -10,10 +10,10 @@ // See the License for the specific language governing permissions and // limitations under the License. import { Injectable } from '@angular/core'; -import { ParamMap, convertToParamMap } from '@angular/router'; +import { ParamMap } from '@angular/router'; import { ApiService } from '@app/core/api'; import { ClusterService } from '@app/core/services'; -import { IAction, Bundle, Cluster, Entities, Host, TypeName } from '@app/core/types'; +import { Bundle, Cluster, Entities, Host, IAction, TypeName } from '@app/core/types'; import { environment } from '@env/environment'; import { switchMap, tap } from 'rxjs/operators'; From 1a2657dc3e74f13ebc22923d27d944c430d6d241 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Tue, 4 Feb 2020 16:11:10 +0300 Subject: [PATCH 28/85] ADCM-1050 removed the attr 'disabled' from validation --- web/src/app/shared/form-elements/field.directive.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/app/shared/form-elements/field.directive.ts b/web/src/app/shared/form-elements/field.directive.ts index 2e50b3fa1b..ab375cad32 100644 --- a/web/src/app/shared/form-elements/field.directive.ts +++ b/web/src/app/shared/form-elements/field.directive.ts @@ -33,7 +33,7 @@ export class FieldDirective extends BaseDirective implements OnInit { get isValid() { const field = this.find(); - return field.disabled || (field.valid && (field.dirty || field.touched)); + return field.valid && (field.dirty || field.touched); } hasError(name: string) { From 734bafcb356e93110f8b6b0610a2b4f5aa309953 Mon Sep 17 00:00:00 2001 From: Konstantin Voschanov Date: Tue, 4 Feb 2020 18:53:21 +0300 Subject: [PATCH 29/85] ADCM-1060 move all python code to /adcm/python --- os/etc/service/init/run | 8 ++++---- {adcm => python/adcm}/__init__.py | 0 {adcm => python/adcm}/dev.py | 0 {adcm => python/adcm}/init_django.py | 0 {adcm => python/adcm}/settings.py | 3 ++- {adcm => python/adcm}/urls.py | 0 {adcm => python/adcm}/wsgi.py | 0 .../ansible}/plugins/action/adcm_add_host.py | 0 .../ansible}/plugins/action/adcm_check.py | 0 .../ansible}/plugins/action/adcm_config.py | 0 .../plugins/action/adcm_delete_host.py | 0 .../ansible}/plugins/action/adcm_state.py | 0 .../ansible}/plugins/lookup/adcm_config.py | 0 .../ansible}/plugins/lookup/adcm_state.py | 0 {api => python/api}/__init__.py | 0 {api => python/api}/api_views.py | 0 {api => python/api}/apps.py | 0 {api => python/api}/cluster_serial.py | 0 {api => python/api}/cluster_views.py | 0 {api => python/api}/docs.py | 0 {api => python/api}/serializers.py | 0 {api => python/api}/stack_serial.py | 0 {api => python/api}/stack_views.py | 0 .../api}/templates/docs-html/document.html | 0 .../api}/templates/docs-html/index.html | 0 .../api}/templates/docs-html/link.html | 0 .../api}/templates/docs-md/document.md | 0 {api => python/api}/templates/docs-md/index.md | 0 {api => python/api}/templates/docs-md/link.md | 0 {api => python/api}/urls.py | 0 {api => python/api}/views.py | 0 {cm => python/cm}/__init__.py | 0 {cm => python/cm}/adcm_config.py | 0 {cm => python/cm}/admin.py | 0 {cm => python/cm}/ansible_plugin.py | 0 {cm => python/cm}/api.py | 0 {cm => python/cm}/apps.py | 0 {cm => python/cm}/bundle.py | 0 {cm => python/cm}/config.py | 6 ++++-- {cm => python/cm}/daemon.py | 0 {cm => python/cm}/errors.py | 0 {cm => python/cm}/inventory.py | 0 {cm => python/cm}/issue.py | 0 {cm => python/cm}/job.py | 2 +- {cm => python/cm}/logger.py | 0 {cm => python/cm}/migrations/0001_initial.py | 0 .../cm}/migrations/0002_auto_20180801_1117.py | 0 .../cm}/migrations/0003_auto_20180829_1020.py | 0 .../cm}/migrations/0004_auto_20180914_1042.py | 0 .../cm}/migrations/0005_auto_20180928_0945.py | 0 .../cm}/migrations/0006_auto_20181009_1135.py | 0 .../cm}/migrations/0007_auto_20181023_1048.py | 0 .../cm}/migrations/0008_auto_20181107_1216.py | 0 .../cm}/migrations/0009_auto_20181113_1112.py | 0 .../cm}/migrations/0010_auto_20181212_1213.py | 0 .../cm}/migrations/0011_auto_20181220_1327.py | 0 .../cm}/migrations/0012_auto_20181226_0926.py | 0 .../cm}/migrations/0013_auto_20190116_1143.py | 0 .../cm}/migrations/0014_auto_20190124_1344.py | 0 .../cm}/migrations/0015_auto_20190128_1142.py | 0 .../cm}/migrations/0016_auto_20190218_1214.py | 0 .../cm}/migrations/0017_auto_20190220_1137.py | 0 .../cm}/migrations/0018_auto_20190220_1101.py | 0 .../cm}/migrations/0019_auto_20190314_1321.py | 0 .../cm}/migrations/0020_auto_20190321_1126.py | 0 .../cm}/migrations/0021_auto_20190607_1027.py | 0 .../cm}/migrations/0022_auto_20190620_1251.py | 0 .../cm}/migrations/0023_auto_20190624_1441.py | 0 .../cm}/migrations/0024_auto_20190715_1548.py | 0 .../cm}/migrations/0025_auto_20190719_1036.py | 0 .../cm}/migrations/0026_auto_20190805_1442.py | 0 .../cm}/migrations/0027_auto_20190809_1134.py | 0 .../cm}/migrations/0028_auto_20190813_1005.py | 0 .../cm}/migrations/0029_auto_20190814_1306.py | 0 .../cm}/migrations/0030_auto_20190820_1600.py | 0 .../cm}/migrations/0031_auto_20190926_1600.py | 0 .../cm}/migrations/0032_auto_20191015_1600.py | 0 .../cm}/migrations/0033_auto_20191023_1459.py | 0 .../cm}/migrations/0034_auto_20191029_1041.py | 0 .../cm}/migrations/0035_auto_20191031_1600.py | 0 .../cm}/migrations/0036_auto_20191111_1109.py | 0 .../cm}/migrations/0037_auto_20191120_1600.py | 0 .../cm}/migrations/0038_auto_20191119_1200.py | 0 .../cm}/migrations/0039_auto_20191203_0909.py | 0 .../cm}/migrations/0040_auto_20191218_1358.py | 0 .../cm}/migrations/0041_auto_20191220_1338.py | 0 .../cm}/migrations/0043_auto_20200109_1600.py | 0 .../cm}/migrations/0044_auto_20200115_1058.py | 0 .../cm}/migrations/0045_auto_20200117_1253.py | 0 .../cm}/migrations/0046_auto_20200120_1417.py | 0 {cm => python/cm}/migrations/__init__.py | 0 {cm => python/cm}/models.py | 0 {cm => python/cm}/stack.py | 0 {cm => python/cm}/static/adcm.css | 0 {cm => python/cm}/static/bootstrap.min.css | 0 {cm => python/cm}/static/starter-template.css | 0 {cm => python/cm}/status_api.py | 0 {cm => python/cm}/templates/base.html | 0 {cm => python/cm}/templates/error.html | 0 {cm => python/cm}/templates/index.html | 0 {cm => python/cm}/templates/token.html | 0 {cm => python/cm}/templates/ws.html | 0 {cm => python/cm}/tests.py | 0 {cm => python/cm}/tests_adcm_config.py | 0 {cm => python/cm}/tests_api.py | 0 {cm => python/cm}/tests_inventory.py | 0 {cm => python/cm}/tests_job.py | 0 {cm => python/cm}/tests_runner.py | 2 +- {cm => python/cm}/upgrade.py | 0 {cm => python/cm}/views.py | 0 drf_docs.py => python/drf_docs.py | 0 init_db.py => python/init_db.py | 0 job_runner.py => python/job_runner.py | 0 manage.py => python/manage.py | 0 pylintrc => python/pylintrc | 0 server.sh => python/server.sh | 0 task_runner.py => python/task_runner.py | 4 ++-- tests/base/run_test.sh | 18 ++++++++++-------- tests/base/settings.py | 5 +++-- 119 files changed, 27 insertions(+), 21 deletions(-) rename {adcm => python/adcm}/__init__.py (100%) rename {adcm => python/adcm}/dev.py (100%) rename {adcm => python/adcm}/init_django.py (100%) rename {adcm => python/adcm}/settings.py (98%) rename {adcm => python/adcm}/urls.py (100%) rename {adcm => python/adcm}/wsgi.py (100%) rename {ansible => python/ansible}/plugins/action/adcm_add_host.py (100%) rename {ansible => python/ansible}/plugins/action/adcm_check.py (100%) rename {ansible => python/ansible}/plugins/action/adcm_config.py (100%) rename {ansible => python/ansible}/plugins/action/adcm_delete_host.py (100%) rename {ansible => python/ansible}/plugins/action/adcm_state.py (100%) rename {ansible => python/ansible}/plugins/lookup/adcm_config.py (100%) rename {ansible => python/ansible}/plugins/lookup/adcm_state.py (100%) rename {api => python/api}/__init__.py (100%) rename {api => python/api}/api_views.py (100%) rename {api => python/api}/apps.py (100%) rename {api => python/api}/cluster_serial.py (100%) rename {api => python/api}/cluster_views.py (100%) rename {api => python/api}/docs.py (100%) rename {api => python/api}/serializers.py (100%) rename {api => python/api}/stack_serial.py (100%) rename {api => python/api}/stack_views.py (100%) rename {api => python/api}/templates/docs-html/document.html (100%) rename {api => python/api}/templates/docs-html/index.html (100%) rename {api => python/api}/templates/docs-html/link.html (100%) rename {api => python/api}/templates/docs-md/document.md (100%) rename {api => python/api}/templates/docs-md/index.md (100%) rename {api => python/api}/templates/docs-md/link.md (100%) rename {api => python/api}/urls.py (100%) rename {api => python/api}/views.py (100%) rename {cm => python/cm}/__init__.py (100%) rename {cm => python/cm}/adcm_config.py (100%) rename {cm => python/cm}/admin.py (100%) rename {cm => python/cm}/ansible_plugin.py (100%) rename {cm => python/cm}/api.py (100%) rename {cm => python/cm}/apps.py (100%) rename {cm => python/cm}/bundle.py (100%) rename {cm => python/cm}/config.py (91%) rename {cm => python/cm}/daemon.py (100%) rename {cm => python/cm}/errors.py (100%) rename {cm => python/cm}/inventory.py (100%) rename {cm => python/cm}/issue.py (100%) rename {cm => python/cm}/job.py (99%) rename {cm => python/cm}/logger.py (100%) rename {cm => python/cm}/migrations/0001_initial.py (100%) rename {cm => python/cm}/migrations/0002_auto_20180801_1117.py (100%) rename {cm => python/cm}/migrations/0003_auto_20180829_1020.py (100%) rename {cm => python/cm}/migrations/0004_auto_20180914_1042.py (100%) rename {cm => python/cm}/migrations/0005_auto_20180928_0945.py (100%) rename {cm => python/cm}/migrations/0006_auto_20181009_1135.py (100%) rename {cm => python/cm}/migrations/0007_auto_20181023_1048.py (100%) rename {cm => python/cm}/migrations/0008_auto_20181107_1216.py (100%) rename {cm => python/cm}/migrations/0009_auto_20181113_1112.py (100%) rename {cm => python/cm}/migrations/0010_auto_20181212_1213.py (100%) rename {cm => python/cm}/migrations/0011_auto_20181220_1327.py (100%) rename {cm => python/cm}/migrations/0012_auto_20181226_0926.py (100%) rename {cm => python/cm}/migrations/0013_auto_20190116_1143.py (100%) rename {cm => python/cm}/migrations/0014_auto_20190124_1344.py (100%) rename {cm => python/cm}/migrations/0015_auto_20190128_1142.py (100%) rename {cm => python/cm}/migrations/0016_auto_20190218_1214.py (100%) rename {cm => python/cm}/migrations/0017_auto_20190220_1137.py (100%) rename {cm => python/cm}/migrations/0018_auto_20190220_1101.py (100%) rename {cm => python/cm}/migrations/0019_auto_20190314_1321.py (100%) rename {cm => python/cm}/migrations/0020_auto_20190321_1126.py (100%) rename {cm => python/cm}/migrations/0021_auto_20190607_1027.py (100%) rename {cm => python/cm}/migrations/0022_auto_20190620_1251.py (100%) rename {cm => python/cm}/migrations/0023_auto_20190624_1441.py (100%) rename {cm => python/cm}/migrations/0024_auto_20190715_1548.py (100%) rename {cm => python/cm}/migrations/0025_auto_20190719_1036.py (100%) rename {cm => python/cm}/migrations/0026_auto_20190805_1442.py (100%) rename {cm => python/cm}/migrations/0027_auto_20190809_1134.py (100%) rename {cm => python/cm}/migrations/0028_auto_20190813_1005.py (100%) rename {cm => python/cm}/migrations/0029_auto_20190814_1306.py (100%) rename {cm => python/cm}/migrations/0030_auto_20190820_1600.py (100%) rename {cm => python/cm}/migrations/0031_auto_20190926_1600.py (100%) rename {cm => python/cm}/migrations/0032_auto_20191015_1600.py (100%) rename {cm => python/cm}/migrations/0033_auto_20191023_1459.py (100%) rename {cm => python/cm}/migrations/0034_auto_20191029_1041.py (100%) rename {cm => python/cm}/migrations/0035_auto_20191031_1600.py (100%) rename {cm => python/cm}/migrations/0036_auto_20191111_1109.py (100%) rename {cm => python/cm}/migrations/0037_auto_20191120_1600.py (100%) rename {cm => python/cm}/migrations/0038_auto_20191119_1200.py (100%) rename {cm => python/cm}/migrations/0039_auto_20191203_0909.py (100%) rename {cm => python/cm}/migrations/0040_auto_20191218_1358.py (100%) rename {cm => python/cm}/migrations/0041_auto_20191220_1338.py (100%) rename {cm => python/cm}/migrations/0043_auto_20200109_1600.py (100%) rename {cm => python/cm}/migrations/0044_auto_20200115_1058.py (100%) rename {cm => python/cm}/migrations/0045_auto_20200117_1253.py (100%) rename {cm => python/cm}/migrations/0046_auto_20200120_1417.py (100%) rename {cm => python/cm}/migrations/__init__.py (100%) rename {cm => python/cm}/models.py (100%) rename {cm => python/cm}/stack.py (100%) rename {cm => python/cm}/static/adcm.css (100%) rename {cm => python/cm}/static/bootstrap.min.css (100%) rename {cm => python/cm}/static/starter-template.css (100%) rename {cm => python/cm}/status_api.py (100%) rename {cm => python/cm}/templates/base.html (100%) rename {cm => python/cm}/templates/error.html (100%) rename {cm => python/cm}/templates/index.html (100%) rename {cm => python/cm}/templates/token.html (100%) rename {cm => python/cm}/templates/ws.html (100%) rename {cm => python/cm}/tests.py (100%) rename {cm => python/cm}/tests_adcm_config.py (100%) rename {cm => python/cm}/tests_api.py (100%) rename {cm => python/cm}/tests_inventory.py (100%) rename {cm => python/cm}/tests_job.py (100%) rename {cm => python/cm}/tests_runner.py (99%) rename {cm => python/cm}/upgrade.py (100%) rename {cm => python/cm}/views.py (100%) rename drf_docs.py => python/drf_docs.py (100%) rename init_db.py => python/init_db.py (100%) rename job_runner.py => python/job_runner.py (100%) rename manage.py => python/manage.py (100%) rename pylintrc => python/pylintrc (100%) rename server.sh => python/server.sh (100%) rename task_runner.py => python/task_runner.py (97%) diff --git a/os/etc/service/init/run b/os/etc/service/init/run index fb4af0cf8b..f7098c72fd 100755 --- a/os/etc/service/init/run +++ b/os/etc/service/init/run @@ -38,13 +38,13 @@ key=/root/.ssh/id_rsa if [ ! -f "${adcmroot}"/var/cluster.db ]; then echo "Assume first run" - "${adcmroot}"/manage.py generate_secret_key "${adcmsecretfile}" - "${adcmroot}"/manage.py migrate + "${adcmroot}"/python/manage.py generate_secret_key "${adcmsecretfile}" + "${adcmroot}"/python/manage.py migrate else - "${adcmroot}"/manage.py migrate + "${adcmroot}"/python/manage.py migrate fi -"${adcmroot}"/init_db.py +"${adcmroot}"/python/init_db.py touch "${initreadyfile}" # That is sleep forever case because I have no idea how to force diff --git a/adcm/__init__.py b/python/adcm/__init__.py similarity index 100% rename from adcm/__init__.py rename to python/adcm/__init__.py diff --git a/adcm/dev.py b/python/adcm/dev.py similarity index 100% rename from adcm/dev.py rename to python/adcm/dev.py diff --git a/adcm/init_django.py b/python/adcm/init_django.py similarity index 100% rename from adcm/init_django.py rename to python/adcm/init_django.py diff --git a/adcm/settings.py b/python/adcm/settings.py similarity index 98% rename from adcm/settings.py rename to python/adcm/settings.py index 579da6011d..700fb5ca58 100644 --- a/adcm/settings.py +++ b/python/adcm/settings.py @@ -23,12 +23,13 @@ import json import os +from os.path import dirname from django.core.management.utils import get_random_secret_key # Build paths inside the project like this: os.path.join(BASE_DIR, ...) -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +BASE_DIR = dirname(dirname(dirname(os.path.abspath(__file__)))) CONF_DIR = BASE_DIR + '/data/conf/' SECRET_KEY_FILE = CONF_DIR + '/secret_key.txt' CONFIG_FILE = BASE_DIR + '/config.json' diff --git a/adcm/urls.py b/python/adcm/urls.py similarity index 100% rename from adcm/urls.py rename to python/adcm/urls.py diff --git a/adcm/wsgi.py b/python/adcm/wsgi.py similarity index 100% rename from adcm/wsgi.py rename to python/adcm/wsgi.py diff --git a/ansible/plugins/action/adcm_add_host.py b/python/ansible/plugins/action/adcm_add_host.py similarity index 100% rename from ansible/plugins/action/adcm_add_host.py rename to python/ansible/plugins/action/adcm_add_host.py diff --git a/ansible/plugins/action/adcm_check.py b/python/ansible/plugins/action/adcm_check.py similarity index 100% rename from ansible/plugins/action/adcm_check.py rename to python/ansible/plugins/action/adcm_check.py diff --git a/ansible/plugins/action/adcm_config.py b/python/ansible/plugins/action/adcm_config.py similarity index 100% rename from ansible/plugins/action/adcm_config.py rename to python/ansible/plugins/action/adcm_config.py diff --git a/ansible/plugins/action/adcm_delete_host.py b/python/ansible/plugins/action/adcm_delete_host.py similarity index 100% rename from ansible/plugins/action/adcm_delete_host.py rename to python/ansible/plugins/action/adcm_delete_host.py diff --git a/ansible/plugins/action/adcm_state.py b/python/ansible/plugins/action/adcm_state.py similarity index 100% rename from ansible/plugins/action/adcm_state.py rename to python/ansible/plugins/action/adcm_state.py diff --git a/ansible/plugins/lookup/adcm_config.py b/python/ansible/plugins/lookup/adcm_config.py similarity index 100% rename from ansible/plugins/lookup/adcm_config.py rename to python/ansible/plugins/lookup/adcm_config.py diff --git a/ansible/plugins/lookup/adcm_state.py b/python/ansible/plugins/lookup/adcm_state.py similarity index 100% rename from ansible/plugins/lookup/adcm_state.py rename to python/ansible/plugins/lookup/adcm_state.py diff --git a/api/__init__.py b/python/api/__init__.py similarity index 100% rename from api/__init__.py rename to python/api/__init__.py diff --git a/api/api_views.py b/python/api/api_views.py similarity index 100% rename from api/api_views.py rename to python/api/api_views.py diff --git a/api/apps.py b/python/api/apps.py similarity index 100% rename from api/apps.py rename to python/api/apps.py diff --git a/api/cluster_serial.py b/python/api/cluster_serial.py similarity index 100% rename from api/cluster_serial.py rename to python/api/cluster_serial.py diff --git a/api/cluster_views.py b/python/api/cluster_views.py similarity index 100% rename from api/cluster_views.py rename to python/api/cluster_views.py diff --git a/api/docs.py b/python/api/docs.py similarity index 100% rename from api/docs.py rename to python/api/docs.py diff --git a/api/serializers.py b/python/api/serializers.py similarity index 100% rename from api/serializers.py rename to python/api/serializers.py diff --git a/api/stack_serial.py b/python/api/stack_serial.py similarity index 100% rename from api/stack_serial.py rename to python/api/stack_serial.py diff --git a/api/stack_views.py b/python/api/stack_views.py similarity index 100% rename from api/stack_views.py rename to python/api/stack_views.py diff --git a/api/templates/docs-html/document.html b/python/api/templates/docs-html/document.html similarity index 100% rename from api/templates/docs-html/document.html rename to python/api/templates/docs-html/document.html diff --git a/api/templates/docs-html/index.html b/python/api/templates/docs-html/index.html similarity index 100% rename from api/templates/docs-html/index.html rename to python/api/templates/docs-html/index.html diff --git a/api/templates/docs-html/link.html b/python/api/templates/docs-html/link.html similarity index 100% rename from api/templates/docs-html/link.html rename to python/api/templates/docs-html/link.html diff --git a/api/templates/docs-md/document.md b/python/api/templates/docs-md/document.md similarity index 100% rename from api/templates/docs-md/document.md rename to python/api/templates/docs-md/document.md diff --git a/api/templates/docs-md/index.md b/python/api/templates/docs-md/index.md similarity index 100% rename from api/templates/docs-md/index.md rename to python/api/templates/docs-md/index.md diff --git a/api/templates/docs-md/link.md b/python/api/templates/docs-md/link.md similarity index 100% rename from api/templates/docs-md/link.md rename to python/api/templates/docs-md/link.md diff --git a/api/urls.py b/python/api/urls.py similarity index 100% rename from api/urls.py rename to python/api/urls.py diff --git a/api/views.py b/python/api/views.py similarity index 100% rename from api/views.py rename to python/api/views.py diff --git a/cm/__init__.py b/python/cm/__init__.py similarity index 100% rename from cm/__init__.py rename to python/cm/__init__.py diff --git a/cm/adcm_config.py b/python/cm/adcm_config.py similarity index 100% rename from cm/adcm_config.py rename to python/cm/adcm_config.py diff --git a/cm/admin.py b/python/cm/admin.py similarity index 100% rename from cm/admin.py rename to python/cm/admin.py diff --git a/cm/ansible_plugin.py b/python/cm/ansible_plugin.py similarity index 100% rename from cm/ansible_plugin.py rename to python/cm/ansible_plugin.py diff --git a/cm/api.py b/python/cm/api.py similarity index 100% rename from cm/api.py rename to python/cm/api.py diff --git a/cm/apps.py b/python/cm/apps.py similarity index 100% rename from cm/apps.py rename to python/cm/apps.py diff --git a/cm/bundle.py b/python/cm/bundle.py similarity index 100% rename from cm/bundle.py rename to python/cm/bundle.py diff --git a/cm/config.py b/python/cm/config.py similarity index 91% rename from cm/config.py rename to python/cm/config.py index 55bee7d3f0..2f5e880a3d 100644 --- a/cm/config.py +++ b/python/cm/config.py @@ -12,14 +12,16 @@ import json import os +from os.path import dirname - -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +BASE_DIR = dirname(dirname(dirname(os.path.abspath(__file__)))) BASE_DIR = os.environ.get('ADCM_BASE_DIR', BASE_DIR) STACK_DIR = BASE_DIR STACK_DIR = os.environ.get('ADCM_STACK_DIR', STACK_DIR) +CODE_DIR = os.path.join(BASE_DIR, 'python') + LOG_DIR = os.path.join(BASE_DIR, 'data', 'log') RUN_DIR = os.path.join(BASE_DIR, 'data', 'run') diff --git a/cm/daemon.py b/python/cm/daemon.py similarity index 100% rename from cm/daemon.py rename to python/cm/daemon.py diff --git a/cm/errors.py b/python/cm/errors.py similarity index 100% rename from cm/errors.py rename to python/cm/errors.py diff --git a/cm/inventory.py b/python/cm/inventory.py similarity index 100% rename from cm/inventory.py rename to python/cm/inventory.py diff --git a/cm/issue.py b/python/cm/issue.py similarity index 100% rename from cm/issue.py rename to python/cm/issue.py diff --git a/cm/job.py b/python/cm/job.py similarity index 99% rename from cm/job.py rename to python/cm/job.py index b9624e17f1..2a195464a4 100644 --- a/cm/job.py +++ b/python/cm/job.py @@ -802,7 +802,7 @@ def check_all_status(): def run_task(task, args=''): err_file = open(os.path.join(config.LOG_DIR, 'task_runner.err'), 'a+') proc = subprocess.Popen([ - os.path.join(config.BASE_DIR, 'task_runner.py'), + os.path.join(config.CODE_DIR, 'task_runner.py'), str(task.id), args ], stderr=err_file) diff --git a/cm/logger.py b/python/cm/logger.py similarity index 100% rename from cm/logger.py rename to python/cm/logger.py diff --git a/cm/migrations/0001_initial.py b/python/cm/migrations/0001_initial.py similarity index 100% rename from cm/migrations/0001_initial.py rename to python/cm/migrations/0001_initial.py diff --git a/cm/migrations/0002_auto_20180801_1117.py b/python/cm/migrations/0002_auto_20180801_1117.py similarity index 100% rename from cm/migrations/0002_auto_20180801_1117.py rename to python/cm/migrations/0002_auto_20180801_1117.py diff --git a/cm/migrations/0003_auto_20180829_1020.py b/python/cm/migrations/0003_auto_20180829_1020.py similarity index 100% rename from cm/migrations/0003_auto_20180829_1020.py rename to python/cm/migrations/0003_auto_20180829_1020.py diff --git a/cm/migrations/0004_auto_20180914_1042.py b/python/cm/migrations/0004_auto_20180914_1042.py similarity index 100% rename from cm/migrations/0004_auto_20180914_1042.py rename to python/cm/migrations/0004_auto_20180914_1042.py diff --git a/cm/migrations/0005_auto_20180928_0945.py b/python/cm/migrations/0005_auto_20180928_0945.py similarity index 100% rename from cm/migrations/0005_auto_20180928_0945.py rename to python/cm/migrations/0005_auto_20180928_0945.py diff --git a/cm/migrations/0006_auto_20181009_1135.py b/python/cm/migrations/0006_auto_20181009_1135.py similarity index 100% rename from cm/migrations/0006_auto_20181009_1135.py rename to python/cm/migrations/0006_auto_20181009_1135.py diff --git a/cm/migrations/0007_auto_20181023_1048.py b/python/cm/migrations/0007_auto_20181023_1048.py similarity index 100% rename from cm/migrations/0007_auto_20181023_1048.py rename to python/cm/migrations/0007_auto_20181023_1048.py diff --git a/cm/migrations/0008_auto_20181107_1216.py b/python/cm/migrations/0008_auto_20181107_1216.py similarity index 100% rename from cm/migrations/0008_auto_20181107_1216.py rename to python/cm/migrations/0008_auto_20181107_1216.py diff --git a/cm/migrations/0009_auto_20181113_1112.py b/python/cm/migrations/0009_auto_20181113_1112.py similarity index 100% rename from cm/migrations/0009_auto_20181113_1112.py rename to python/cm/migrations/0009_auto_20181113_1112.py diff --git a/cm/migrations/0010_auto_20181212_1213.py b/python/cm/migrations/0010_auto_20181212_1213.py similarity index 100% rename from cm/migrations/0010_auto_20181212_1213.py rename to python/cm/migrations/0010_auto_20181212_1213.py diff --git a/cm/migrations/0011_auto_20181220_1327.py b/python/cm/migrations/0011_auto_20181220_1327.py similarity index 100% rename from cm/migrations/0011_auto_20181220_1327.py rename to python/cm/migrations/0011_auto_20181220_1327.py diff --git a/cm/migrations/0012_auto_20181226_0926.py b/python/cm/migrations/0012_auto_20181226_0926.py similarity index 100% rename from cm/migrations/0012_auto_20181226_0926.py rename to python/cm/migrations/0012_auto_20181226_0926.py diff --git a/cm/migrations/0013_auto_20190116_1143.py b/python/cm/migrations/0013_auto_20190116_1143.py similarity index 100% rename from cm/migrations/0013_auto_20190116_1143.py rename to python/cm/migrations/0013_auto_20190116_1143.py diff --git a/cm/migrations/0014_auto_20190124_1344.py b/python/cm/migrations/0014_auto_20190124_1344.py similarity index 100% rename from cm/migrations/0014_auto_20190124_1344.py rename to python/cm/migrations/0014_auto_20190124_1344.py diff --git a/cm/migrations/0015_auto_20190128_1142.py b/python/cm/migrations/0015_auto_20190128_1142.py similarity index 100% rename from cm/migrations/0015_auto_20190128_1142.py rename to python/cm/migrations/0015_auto_20190128_1142.py diff --git a/cm/migrations/0016_auto_20190218_1214.py b/python/cm/migrations/0016_auto_20190218_1214.py similarity index 100% rename from cm/migrations/0016_auto_20190218_1214.py rename to python/cm/migrations/0016_auto_20190218_1214.py diff --git a/cm/migrations/0017_auto_20190220_1137.py b/python/cm/migrations/0017_auto_20190220_1137.py similarity index 100% rename from cm/migrations/0017_auto_20190220_1137.py rename to python/cm/migrations/0017_auto_20190220_1137.py diff --git a/cm/migrations/0018_auto_20190220_1101.py b/python/cm/migrations/0018_auto_20190220_1101.py similarity index 100% rename from cm/migrations/0018_auto_20190220_1101.py rename to python/cm/migrations/0018_auto_20190220_1101.py diff --git a/cm/migrations/0019_auto_20190314_1321.py b/python/cm/migrations/0019_auto_20190314_1321.py similarity index 100% rename from cm/migrations/0019_auto_20190314_1321.py rename to python/cm/migrations/0019_auto_20190314_1321.py diff --git a/cm/migrations/0020_auto_20190321_1126.py b/python/cm/migrations/0020_auto_20190321_1126.py similarity index 100% rename from cm/migrations/0020_auto_20190321_1126.py rename to python/cm/migrations/0020_auto_20190321_1126.py diff --git a/cm/migrations/0021_auto_20190607_1027.py b/python/cm/migrations/0021_auto_20190607_1027.py similarity index 100% rename from cm/migrations/0021_auto_20190607_1027.py rename to python/cm/migrations/0021_auto_20190607_1027.py diff --git a/cm/migrations/0022_auto_20190620_1251.py b/python/cm/migrations/0022_auto_20190620_1251.py similarity index 100% rename from cm/migrations/0022_auto_20190620_1251.py rename to python/cm/migrations/0022_auto_20190620_1251.py diff --git a/cm/migrations/0023_auto_20190624_1441.py b/python/cm/migrations/0023_auto_20190624_1441.py similarity index 100% rename from cm/migrations/0023_auto_20190624_1441.py rename to python/cm/migrations/0023_auto_20190624_1441.py diff --git a/cm/migrations/0024_auto_20190715_1548.py b/python/cm/migrations/0024_auto_20190715_1548.py similarity index 100% rename from cm/migrations/0024_auto_20190715_1548.py rename to python/cm/migrations/0024_auto_20190715_1548.py diff --git a/cm/migrations/0025_auto_20190719_1036.py b/python/cm/migrations/0025_auto_20190719_1036.py similarity index 100% rename from cm/migrations/0025_auto_20190719_1036.py rename to python/cm/migrations/0025_auto_20190719_1036.py diff --git a/cm/migrations/0026_auto_20190805_1442.py b/python/cm/migrations/0026_auto_20190805_1442.py similarity index 100% rename from cm/migrations/0026_auto_20190805_1442.py rename to python/cm/migrations/0026_auto_20190805_1442.py diff --git a/cm/migrations/0027_auto_20190809_1134.py b/python/cm/migrations/0027_auto_20190809_1134.py similarity index 100% rename from cm/migrations/0027_auto_20190809_1134.py rename to python/cm/migrations/0027_auto_20190809_1134.py diff --git a/cm/migrations/0028_auto_20190813_1005.py b/python/cm/migrations/0028_auto_20190813_1005.py similarity index 100% rename from cm/migrations/0028_auto_20190813_1005.py rename to python/cm/migrations/0028_auto_20190813_1005.py diff --git a/cm/migrations/0029_auto_20190814_1306.py b/python/cm/migrations/0029_auto_20190814_1306.py similarity index 100% rename from cm/migrations/0029_auto_20190814_1306.py rename to python/cm/migrations/0029_auto_20190814_1306.py diff --git a/cm/migrations/0030_auto_20190820_1600.py b/python/cm/migrations/0030_auto_20190820_1600.py similarity index 100% rename from cm/migrations/0030_auto_20190820_1600.py rename to python/cm/migrations/0030_auto_20190820_1600.py diff --git a/cm/migrations/0031_auto_20190926_1600.py b/python/cm/migrations/0031_auto_20190926_1600.py similarity index 100% rename from cm/migrations/0031_auto_20190926_1600.py rename to python/cm/migrations/0031_auto_20190926_1600.py diff --git a/cm/migrations/0032_auto_20191015_1600.py b/python/cm/migrations/0032_auto_20191015_1600.py similarity index 100% rename from cm/migrations/0032_auto_20191015_1600.py rename to python/cm/migrations/0032_auto_20191015_1600.py diff --git a/cm/migrations/0033_auto_20191023_1459.py b/python/cm/migrations/0033_auto_20191023_1459.py similarity index 100% rename from cm/migrations/0033_auto_20191023_1459.py rename to python/cm/migrations/0033_auto_20191023_1459.py diff --git a/cm/migrations/0034_auto_20191029_1041.py b/python/cm/migrations/0034_auto_20191029_1041.py similarity index 100% rename from cm/migrations/0034_auto_20191029_1041.py rename to python/cm/migrations/0034_auto_20191029_1041.py diff --git a/cm/migrations/0035_auto_20191031_1600.py b/python/cm/migrations/0035_auto_20191031_1600.py similarity index 100% rename from cm/migrations/0035_auto_20191031_1600.py rename to python/cm/migrations/0035_auto_20191031_1600.py diff --git a/cm/migrations/0036_auto_20191111_1109.py b/python/cm/migrations/0036_auto_20191111_1109.py similarity index 100% rename from cm/migrations/0036_auto_20191111_1109.py rename to python/cm/migrations/0036_auto_20191111_1109.py diff --git a/cm/migrations/0037_auto_20191120_1600.py b/python/cm/migrations/0037_auto_20191120_1600.py similarity index 100% rename from cm/migrations/0037_auto_20191120_1600.py rename to python/cm/migrations/0037_auto_20191120_1600.py diff --git a/cm/migrations/0038_auto_20191119_1200.py b/python/cm/migrations/0038_auto_20191119_1200.py similarity index 100% rename from cm/migrations/0038_auto_20191119_1200.py rename to python/cm/migrations/0038_auto_20191119_1200.py diff --git a/cm/migrations/0039_auto_20191203_0909.py b/python/cm/migrations/0039_auto_20191203_0909.py similarity index 100% rename from cm/migrations/0039_auto_20191203_0909.py rename to python/cm/migrations/0039_auto_20191203_0909.py diff --git a/cm/migrations/0040_auto_20191218_1358.py b/python/cm/migrations/0040_auto_20191218_1358.py similarity index 100% rename from cm/migrations/0040_auto_20191218_1358.py rename to python/cm/migrations/0040_auto_20191218_1358.py diff --git a/cm/migrations/0041_auto_20191220_1338.py b/python/cm/migrations/0041_auto_20191220_1338.py similarity index 100% rename from cm/migrations/0041_auto_20191220_1338.py rename to python/cm/migrations/0041_auto_20191220_1338.py diff --git a/cm/migrations/0043_auto_20200109_1600.py b/python/cm/migrations/0043_auto_20200109_1600.py similarity index 100% rename from cm/migrations/0043_auto_20200109_1600.py rename to python/cm/migrations/0043_auto_20200109_1600.py diff --git a/cm/migrations/0044_auto_20200115_1058.py b/python/cm/migrations/0044_auto_20200115_1058.py similarity index 100% rename from cm/migrations/0044_auto_20200115_1058.py rename to python/cm/migrations/0044_auto_20200115_1058.py diff --git a/cm/migrations/0045_auto_20200117_1253.py b/python/cm/migrations/0045_auto_20200117_1253.py similarity index 100% rename from cm/migrations/0045_auto_20200117_1253.py rename to python/cm/migrations/0045_auto_20200117_1253.py diff --git a/cm/migrations/0046_auto_20200120_1417.py b/python/cm/migrations/0046_auto_20200120_1417.py similarity index 100% rename from cm/migrations/0046_auto_20200120_1417.py rename to python/cm/migrations/0046_auto_20200120_1417.py diff --git a/cm/migrations/__init__.py b/python/cm/migrations/__init__.py similarity index 100% rename from cm/migrations/__init__.py rename to python/cm/migrations/__init__.py diff --git a/cm/models.py b/python/cm/models.py similarity index 100% rename from cm/models.py rename to python/cm/models.py diff --git a/cm/stack.py b/python/cm/stack.py similarity index 100% rename from cm/stack.py rename to python/cm/stack.py diff --git a/cm/static/adcm.css b/python/cm/static/adcm.css similarity index 100% rename from cm/static/adcm.css rename to python/cm/static/adcm.css diff --git a/cm/static/bootstrap.min.css b/python/cm/static/bootstrap.min.css similarity index 100% rename from cm/static/bootstrap.min.css rename to python/cm/static/bootstrap.min.css diff --git a/cm/static/starter-template.css b/python/cm/static/starter-template.css similarity index 100% rename from cm/static/starter-template.css rename to python/cm/static/starter-template.css diff --git a/cm/status_api.py b/python/cm/status_api.py similarity index 100% rename from cm/status_api.py rename to python/cm/status_api.py diff --git a/cm/templates/base.html b/python/cm/templates/base.html similarity index 100% rename from cm/templates/base.html rename to python/cm/templates/base.html diff --git a/cm/templates/error.html b/python/cm/templates/error.html similarity index 100% rename from cm/templates/error.html rename to python/cm/templates/error.html diff --git a/cm/templates/index.html b/python/cm/templates/index.html similarity index 100% rename from cm/templates/index.html rename to python/cm/templates/index.html diff --git a/cm/templates/token.html b/python/cm/templates/token.html similarity index 100% rename from cm/templates/token.html rename to python/cm/templates/token.html diff --git a/cm/templates/ws.html b/python/cm/templates/ws.html similarity index 100% rename from cm/templates/ws.html rename to python/cm/templates/ws.html diff --git a/cm/tests.py b/python/cm/tests.py similarity index 100% rename from cm/tests.py rename to python/cm/tests.py diff --git a/cm/tests_adcm_config.py b/python/cm/tests_adcm_config.py similarity index 100% rename from cm/tests_adcm_config.py rename to python/cm/tests_adcm_config.py diff --git a/cm/tests_api.py b/python/cm/tests_api.py similarity index 100% rename from cm/tests_api.py rename to python/cm/tests_api.py diff --git a/cm/tests_inventory.py b/python/cm/tests_inventory.py similarity index 100% rename from cm/tests_inventory.py rename to python/cm/tests_inventory.py diff --git a/cm/tests_job.py b/python/cm/tests_job.py similarity index 100% rename from cm/tests_job.py rename to python/cm/tests_job.py diff --git a/cm/tests_runner.py b/python/cm/tests_runner.py similarity index 99% rename from cm/tests_runner.py rename to python/cm/tests_runner.py index 309e0e96ae..b05180921f 100644 --- a/cm/tests_runner.py +++ b/python/cm/tests_runner.py @@ -86,7 +86,7 @@ def test_run_job(self, mock_subprocess_popen): mock_subprocess_popen.return_value = process_mock code = task_runner.run_job(1, 1, '', '') cmd = [ - '{}/job_runner.py'.format(config.BASE_DIR), + '{}/job_runner.py'.format(config.CODE_DIR), str(1) ] mock_subprocess_popen.assert_called_once_with(cmd, stdout='', stderr='') diff --git a/cm/upgrade.py b/python/cm/upgrade.py similarity index 100% rename from cm/upgrade.py rename to python/cm/upgrade.py diff --git a/cm/views.py b/python/cm/views.py similarity index 100% rename from cm/views.py rename to python/cm/views.py diff --git a/drf_docs.py b/python/drf_docs.py similarity index 100% rename from drf_docs.py rename to python/drf_docs.py diff --git a/init_db.py b/python/init_db.py similarity index 100% rename from init_db.py rename to python/init_db.py diff --git a/job_runner.py b/python/job_runner.py similarity index 100% rename from job_runner.py rename to python/job_runner.py diff --git a/manage.py b/python/manage.py similarity index 100% rename from manage.py rename to python/manage.py diff --git a/pylintrc b/python/pylintrc similarity index 100% rename from pylintrc rename to python/pylintrc diff --git a/server.sh b/python/server.sh similarity index 100% rename from server.sh rename to python/server.sh diff --git a/task_runner.py b/python/task_runner.py similarity index 97% rename from task_runner.py rename to python/task_runner.py index 2d0804780f..8d1ea8dbc8 100755 --- a/task_runner.py +++ b/python/task_runner.py @@ -71,7 +71,7 @@ def terminate_task(signum, frame): def open_file(root, tag, task_id): - fname = "{}/{}-{}.txt".format(root, task_id, tag) + fname = os.path.join(root, f'{task_id}-{tag}.txt') f = open(fname, 'w') return f @@ -80,7 +80,7 @@ def run_job(task_id, job_id, out_file, err_file): log.debug("run job #%s of task #%s", job_id, task_id) try: proc = subprocess.Popen([ - '{}/job_runner.py'.format(config.BASE_DIR), + os.path.join(config.CODE_DIR, 'job_runner.py'), str(job_id) ], stdout=out_file, stderr=err_file) res = proc.wait() diff --git a/tests/base/run_test.sh b/tests/base/run_test.sh index 93568ab570..0707541a5a 100755 --- a/tests/base/run_test.sh +++ b/tests/base/run_test.sh @@ -13,14 +13,16 @@ port=8040 -export DJANGO_SETTINGS_MODULE=tests.base.settings -export ADCM_STACK_DIR="tests/base" +export PYTHONPATH="$(dirname `pwd`)" +export DJANGO_SETTINGS_MODULE=base.settings +export ADCM_STACK_DIR="../tests/base" +BASE_DIR="../../python" init_db() { rm -f db_test.db - ../../manage.py migrate - ../../init_db.py + ${BASE_DIR}/manage.py migrate + ${BASE_DIR}/init_db.py cp db_test.db fixture.db } @@ -28,14 +30,14 @@ init_db() { run_debug() { rm -f db_test.db cp fixture.db db_test.db - ../../manage.py runserver 8040 + ${BASE_DIR}/manage.py runserver 8040 } run_test() { rm -f db_test.db cp fixture.db db_test.db - cd ../.. || exit 1 + cd ${BASE_DIR} || exit 1 ./server.sh start "${port}" echo "tests/base/test_api.py ${1} ${2}" TEST_CASE="" @@ -48,9 +50,9 @@ run_test() { fi; done if [[ "$TEST_CASE" != '' ]]; then - ./tests/base/test_api.py "$TEST_CASE" + ../tests/base/test_api.py "$TEST_CASE" else - ./tests/base/test_api.py + ../tests/base/test_api.py fi; ./server.sh stop } diff --git a/tests/base/settings.py b/tests/base/settings.py index 67ce13ab87..a054180b24 100644 --- a/tests/base/settings.py +++ b/tests/base/settings.py @@ -22,9 +22,10 @@ """ import os +from os.path import dirname # Build paths inside the project like this: os.path.join(BASE_DIR, ...) -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +BASE_DIR = dirname(dirname(dirname(os.path.abspath(__file__)))) # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ @@ -107,7 +108,7 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'base/db_test.db'), + 'NAME': os.path.join(BASE_DIR, 'tests/base/db_test.db'), # 'ENGINE': 'django.db.backends.postgresql', # 'NAME': 'adcm', # 'HOST': 'localhost', From 4ad0b533084fe6b4beb0c0fd52754a850783cb15 Mon Sep 17 00:00:00 2001 From: Konstantin Voschanov Date: Tue, 4 Feb 2020 19:12:57 +0300 Subject: [PATCH 30/85] ADCM-1060 fix path to ansible modules in Dockerfile --- Dockerfile | 2 +- tests/pylintrc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 120000 tests/pylintrc diff --git a/Dockerfile b/Dockerfile index 484472d5b0..10d7770f24 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM arenadata/adcmbase:20200203174702 COPY . /adcm/ -RUN cp -r /adcm/os/* / && rm -rf /adcm/os; cp -r /adcm/ansible/* /usr/local/lib/python3.8/site-packages/ansible/ && rm -rf /adcm/ansible && rmdir /var/log/nginx; +RUN cp -r /adcm/os/* / && rm -rf /adcm/os; cp -r /adcm/python/ansible/* /usr/local/lib/python3.8/site-packages/ansible/ && rm -rf /adcm/python/ansible && rmdir /var/log/nginx; # Secret_key is mandatory for build_static procedure, # but should not be hardcoded in the image. diff --git a/tests/pylintrc b/tests/pylintrc new file mode 120000 index 0000000000..34ab9924e9 --- /dev/null +++ b/tests/pylintrc @@ -0,0 +1 @@ +../python/pylintrc \ No newline at end of file From ceac957eb886f23bc481980a147c82c9663b50a3 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Tue, 4 Feb 2020 19:17:48 +0300 Subject: [PATCH 31/85] ADCM-1050 has added fake validation --- web/src/app/shared/configuration/field.service.ts | 1 + web/src/app/shared/configuration/main/main.component.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/web/src/app/shared/configuration/field.service.ts b/web/src/app/shared/configuration/field.service.ts index 85f312245c..a32d16dd8a 100644 --- a/web/src/app/shared/configuration/field.service.ts +++ b/web/src/app/shared/configuration/field.service.ts @@ -125,6 +125,7 @@ export class FieldService { toFormGroup(options: (FieldOptions | PanelOptions)[]): FormGroup { this.form = this.fb.group(options.reduce((p, c) => this.runByTree(c, p), {})); + if (!this.dataOptions.filter(a => !a.hidden).length) this.form.setErrors({ error: 'Ther are not visible fields in this form' }); return this.form; } diff --git a/web/src/app/shared/configuration/main/main.component.ts b/web/src/app/shared/configuration/main/main.component.ts index c33327fde8..d24829495e 100644 --- a/web/src/app/shared/configuration/main/main.component.ts +++ b/web/src/app/shared/configuration/main/main.component.ts @@ -146,7 +146,7 @@ export class ConfigComponent extends SocketListener implements OnInit { this.saveFlag = false; /** * TODO: history does not update! - * => her need the new this.field.dataOptions + * => need the new this.field.dataOptions */ this.historyComponent.versionID = c.id; this.historyComponent.getData(); From 1217297cd5c277fcf9aeb0f76464d37b232ba073 Mon Sep 17 00:00:00 2001 From: Konstantin Voschanov Date: Tue, 4 Feb 2020 19:26:53 +0300 Subject: [PATCH 32/85] ADCM-1060 fix build script --- web/build_static.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/build_static.sh b/web/build_static.sh index 6ae1c7476b..3e1ba7b0a5 100755 --- a/web/build_static.sh +++ b/web/build_static.sh @@ -21,7 +21,7 @@ cd "${workdir}/../" # So we temporary make that dir to remove after operation. mkdir -p data/log -python manage.py collectstatic --noinput +python python/manage.py collectstatic --noinput cp ./wwwroot/static/rest_framework/css/* ./wwwroot/static/rest_framework/docs/css/ From b97c6dded86bb4397644d52a43b1c96cd4fa89c6 Mon Sep 17 00:00:00 2001 From: Konstantin Voschanov Date: Tue, 4 Feb 2020 19:51:35 +0300 Subject: [PATCH 33/85] ADCM-1060 fix django tests in Makefile --- Makefile | 2 +- tests/base/run_test.sh | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index e1aa66d2dc..19fe847ccc 100644 --- a/Makefile +++ b/Makefile @@ -64,4 +64,4 @@ npm_check: ## Run npm-check django_tests : ## Run django tests. docker pull $(ADCMBASE_IMAGE):$(ADCMBASE_TAG) - docker run -i --rm -v $(CURDIR)/:/adcm -w /adcm/ $(ADCMBASE_IMAGE):$(ADCMBASE_TAG) python manage.py test cm + docker run -i --rm -v $(CURDIR)/:/adcm -w /adcm/ $(ADCMBASE_IMAGE):$(ADCMBASE_TAG) python python/manage.py test cm diff --git a/tests/base/run_test.sh b/tests/base/run_test.sh index 0707541a5a..78d52832d4 100755 --- a/tests/base/run_test.sh +++ b/tests/base/run_test.sh @@ -13,7 +13,8 @@ port=8040 -export PYTHONPATH="$(dirname `pwd`)" +PWD="`pwd`" +export PYTHONPATH="$(dirname ${PWD})" export DJANGO_SETTINGS_MODULE=base.settings export ADCM_STACK_DIR="../tests/base" From a6ca0361206c0ebf4eabf5506551a542a75ca3db Mon Sep 17 00:00:00 2001 From: Anton Chevychalov Date: Wed, 5 Feb 2020 11:12:12 +0300 Subject: [PATCH 34/85] ADCM-1060 Change PYTHONPATH in run_test.sh PYTHONPATH should be calculated from run_test.sh dir over $0 variable --- tests/base/run_test.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/base/run_test.sh b/tests/base/run_test.sh index 78d52832d4..f6f7aace62 100755 --- a/tests/base/run_test.sh +++ b/tests/base/run_test.sh @@ -13,8 +13,7 @@ port=8040 -PWD="`pwd`" -export PYTHONPATH="$(dirname ${PWD})" +export PYTHONPATH="$(dirname ${0})" export DJANGO_SETTINGS_MODULE=base.settings export ADCM_STACK_DIR="../tests/base" From 3a64761c8754b462aa7fc0c829459bdaadc7dbff Mon Sep 17 00:00:00 2001 From: Anton Chevychalov Date: Wed, 5 Feb 2020 11:17:07 +0300 Subject: [PATCH 35/85] ADCM-1060 PYTHONPATH one level above run_test.sh --- tests/base/run_test.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/base/run_test.sh b/tests/base/run_test.sh index f6f7aace62..981ea01bca 100755 --- a/tests/base/run_test.sh +++ b/tests/base/run_test.sh @@ -13,7 +13,8 @@ port=8040 -export PYTHONPATH="$(dirname ${0})" +# shellcheck disable=SC2086,SC2155 +export PYTHONPATH="$(dirname ${0})/../" # One level above directory with run_test.sh export DJANGO_SETTINGS_MODULE=base.settings export ADCM_STACK_DIR="../tests/base" From d0321f1a56a199ae184486278f8285c9da7e463c Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Wed, 5 Feb 2020 11:19:00 +0300 Subject: [PATCH 36/85] ADCM-1050 removed the attr 'disabled' from validation #2 --- web/src/app/shared/configuration/field.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/app/shared/configuration/field.service.ts b/web/src/app/shared/configuration/field.service.ts index a32d16dd8a..d341c9934e 100644 --- a/web/src/app/shared/configuration/field.service.ts +++ b/web/src/app/shared/configuration/field.service.ts @@ -125,7 +125,7 @@ export class FieldService { toFormGroup(options: (FieldOptions | PanelOptions)[]): FormGroup { this.form = this.fb.group(options.reduce((p, c) => this.runByTree(c, p), {})); - if (!this.dataOptions.filter(a => !a.hidden).length) this.form.setErrors({ error: 'Ther are not visible fields in this form' }); + if (!this.dataOptions.filter(a => !a.read_only).length) this.form.setErrors({ error: 'Ther are not visible fields in this form' }); return this.form; } From 6ee6840091f7aa5413b59b172dc3178e329eb810 Mon Sep 17 00:00:00 2001 From: Konstantin Voschanov Date: Wed, 5 Feb 2020 11:56:13 +0300 Subject: [PATCH 37/85] ADCM-1060 fix run_test.sh --- python/pylintrc => pylintrc | 0 tests/base/run_test.sh | 2 +- tests/pylintrc | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) rename python/pylintrc => pylintrc (100%) delete mode 120000 tests/pylintrc diff --git a/python/pylintrc b/pylintrc similarity index 100% rename from python/pylintrc rename to pylintrc diff --git a/tests/base/run_test.sh b/tests/base/run_test.sh index 981ea01bca..36588c2de7 100755 --- a/tests/base/run_test.sh +++ b/tests/base/run_test.sh @@ -14,7 +14,7 @@ port=8040 # shellcheck disable=SC2086,SC2155 -export PYTHONPATH="$(dirname ${0})/../" # One level above directory with run_test.sh +export PYTHONPATH="$(dirname `pwd`)" export DJANGO_SETTINGS_MODULE=base.settings export ADCM_STACK_DIR="../tests/base" diff --git a/tests/pylintrc b/tests/pylintrc deleted file mode 120000 index 34ab9924e9..0000000000 --- a/tests/pylintrc +++ /dev/null @@ -1 +0,0 @@ -../python/pylintrc \ No newline at end of file From 587dcaee37e9a9c6038c33659303acb08846a3d4 Mon Sep 17 00:00:00 2001 From: Konstantin Voschanov Date: Wed, 5 Feb 2020 12:14:25 +0300 Subject: [PATCH 38/85] ADCM-1060 fix amsible plugins --- python/ansible/plugins/action/adcm_add_host.py | 2 +- python/ansible/plugins/action/adcm_check.py | 2 +- python/ansible/plugins/action/adcm_config.py | 2 +- python/ansible/plugins/action/adcm_delete_host.py | 2 +- python/ansible/plugins/action/adcm_state.py | 2 +- tests/base/run_test.sh | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/python/ansible/plugins/action/adcm_add_host.py b/python/ansible/plugins/action/adcm_add_host.py index 2569e9f4a1..9cc043007e 100644 --- a/python/ansible/plugins/action/adcm_add_host.py +++ b/python/ansible/plugins/action/adcm_add_host.py @@ -52,7 +52,7 @@ from ansible.errors import AnsibleError from ansible.plugins.action import ActionBase -sys.path.append('/adcm') +sys.path.append('/adcm/python') import adcm.init_django import cm.api from cm.ansible_plugin import get_context_id diff --git a/python/ansible/plugins/action/adcm_check.py b/python/ansible/plugins/action/adcm_check.py index 5832728460..92cae038e1 100644 --- a/python/ansible/plugins/action/adcm_check.py +++ b/python/ansible/plugins/action/adcm_check.py @@ -58,7 +58,7 @@ import sys from ansible.plugins.action import ActionBase -sys.path.append('/adcm') +sys.path.append('/adcm/python') import adcm.init_django import cm.job from cm.errors import AdcmEx diff --git a/python/ansible/plugins/action/adcm_config.py b/python/ansible/plugins/action/adcm_config.py index f0a11216ad..f33f318c84 100644 --- a/python/ansible/plugins/action/adcm_config.py +++ b/python/ansible/plugins/action/adcm_config.py @@ -16,7 +16,7 @@ __metaclass__ = type import sys -sys.path.append('/adcm') +sys.path.append('/adcm/python') import adcm.init_django from cm.ansible_plugin import ContextActionModule diff --git a/python/ansible/plugins/action/adcm_delete_host.py b/python/ansible/plugins/action/adcm_delete_host.py index 7105b28286..54ed7d2de5 100644 --- a/python/ansible/plugins/action/adcm_delete_host.py +++ b/python/ansible/plugins/action/adcm_delete_host.py @@ -40,7 +40,7 @@ from ansible.errors import AnsibleError from ansible.plugins.action import ActionBase -sys.path.append('/adcm') +sys.path.append('/adcm/python') import adcm.init_django import cm.api from cm.ansible_plugin import get_context_id diff --git a/python/ansible/plugins/action/adcm_state.py b/python/ansible/plugins/action/adcm_state.py index 23fac72f64..274685e992 100644 --- a/python/ansible/plugins/action/adcm_state.py +++ b/python/ansible/plugins/action/adcm_state.py @@ -15,7 +15,7 @@ __metaclass__ = type import sys -sys.path.append('/adcm') +sys.path.append('/adcm/python') import adcm.init_django from cm.ansible_plugin import ContextActionModule diff --git a/tests/base/run_test.sh b/tests/base/run_test.sh index 36588c2de7..00daf2de8f 100755 --- a/tests/base/run_test.sh +++ b/tests/base/run_test.sh @@ -13,7 +13,7 @@ port=8040 -# shellcheck disable=SC2086,SC2155 +# shellcheck disable=SC2086,SC2155,SC2046 export PYTHONPATH="$(dirname `pwd`)" export DJANGO_SETTINGS_MODULE=base.settings export ADCM_STACK_DIR="../tests/base" From 4973946ec34b23eda044bb94b8dc5dd00ca05548 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Wed, 5 Feb 2020 13:13:30 +0300 Subject: [PATCH 39/85] ADCM-1050 has added fake validation#2 --- web/src/app/shared/configuration/field.service.ts | 3 +-- .../shared/configuration/fields/fields.component.ts | 5 +++++ .../app/shared/configuration/main/main.component.html | 2 +- .../app/shared/configuration/main/main.component.ts | 11 +++++++++++ web/src/app/shared/form-elements/field.directive.ts | 2 +- 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/web/src/app/shared/configuration/field.service.ts b/web/src/app/shared/configuration/field.service.ts index d341c9934e..b08b4624c1 100644 --- a/web/src/app/shared/configuration/field.service.ts +++ b/web/src/app/shared/configuration/field.service.ts @@ -124,8 +124,7 @@ export class FieldService { } toFormGroup(options: (FieldOptions | PanelOptions)[]): FormGroup { - this.form = this.fb.group(options.reduce((p, c) => this.runByTree(c, p), {})); - if (!this.dataOptions.filter(a => !a.read_only).length) this.form.setErrors({ error: 'Ther are not visible fields in this form' }); + this.form = this.fb.group(options.reduce((p, c) => this.runByTree(c, p), {})); return this.form; } diff --git a/web/src/app/shared/configuration/fields/fields.component.ts b/web/src/app/shared/configuration/fields/fields.component.ts index d2fe238bd2..8e709fb03f 100644 --- a/web/src/app/shared/configuration/fields/fields.component.ts +++ b/web/src/app/shared/configuration/fields/fields.component.ts @@ -47,12 +47,17 @@ export class ConfigFieldsComponent { set model(data: IConfig) { this.dataOptions = this.service.getPanels(data); this.form = this.service.toFormGroup(this.dataOptions); + this.checkForm(); this.shapshot = { ...this.form.value }; this.event.emit({ name: 'load', data: { form: this.form } }); } constructor(private service: FieldService) {} + checkForm() { + if (!this.dataOptions.filter(a => !a.read_only).length) this.form.setErrors({ error: 'Ther are not visible fields in this form' }); + } + panelsOnly(item: FieldOptions | PanelOptions) { return 'options' in item && !item.hidden; } diff --git a/web/src/app/shared/configuration/main/main.component.html b/web/src/app/shared/configuration/main/main.component.html index dfddc68d7a..616c65c8c2 100644 --- a/web/src/app/shared/configuration/main/main.component.html +++ b/web/src/app/shared/configuration/main/main.component.html @@ -10,6 +10,6 @@ (version)="changeVersion($event)">
- +
diff --git a/web/src/app/shared/configuration/main/main.component.ts b/web/src/app/shared/configuration/main/main.component.ts index d24829495e..1c87221466 100644 --- a/web/src/app/shared/configuration/main/main.component.ts +++ b/web/src/app/shared/configuration/main/main.component.ts @@ -24,6 +24,7 @@ import { ConfigFieldsComponent } from '../fields/fields.component'; import { HistoryComponent } from '../tools/history.component'; import { ToolsComponent } from '../tools/tools.component'; import { IConfig } from '../types'; +import { FormGroup } from '@angular/forms'; @Component({ selector: 'app-config-form', @@ -92,6 +93,15 @@ export class ConfigComponent extends SocketListener implements OnInit { this[toolsEvent.name](toolsEvent.conditions); } + fieldsEvents(e: { name: 'load'; data: { form: FormGroup } }) { + if (e.name === 'load') { + setTimeout(_ => { + this.fields.checkForm(); + this.cdRef.detectChanges(); + }, 0); + } + } + get formValid() { return this.service.form.valid; } @@ -102,6 +112,7 @@ export class ConfigComponent extends SocketListener implements OnInit { filter(c: { advanced: boolean; search: string }) { this.fields.dataOptions = this.service.filterApply(c); + this.fields.checkForm(); } socketListener(m: EventMessage) { diff --git a/web/src/app/shared/form-elements/field.directive.ts b/web/src/app/shared/form-elements/field.directive.ts index ab375cad32..562b647a44 100644 --- a/web/src/app/shared/form-elements/field.directive.ts +++ b/web/src/app/shared/form-elements/field.directive.ts @@ -33,7 +33,7 @@ export class FieldDirective extends BaseDirective implements OnInit { get isValid() { const field = this.find(); - return field.valid && (field.dirty || field.touched); + return this.field.read_only || field.valid && (field.dirty || field.touched); } hasError(name: string) { From a284310480bdffb76f3e12b7870910e3938e2da2 Mon Sep 17 00:00:00 2001 From: Anton Chevychalov Date: Wed, 5 Feb 2020 13:48:21 +0300 Subject: [PATCH 40/85] ADCM-1060 Fixup run script for wsgi --- os/etc/service/wsgi/run | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/os/etc/service/wsgi/run b/os/etc/service/wsgi/run index 71227fbe9c..ca2c9be4cf 100755 --- a/os/etc/service/wsgi/run +++ b/os/etc/service/wsgi/run @@ -19,5 +19,5 @@ echo "Run main wsgi application ..." exec 1>"${adcmlog}/service_wsgi.out" exec 2>"${adcmlog}/service_wsgi.err" -cd "${adcmroot}" +cd "${adcmroot}/python" uwsgi --socket "${wsgisocketfile}" --pidfile "/run/uwsgi.pid" --module adcm.wsgi --chmod-socket=777 --logger file:logfile="${adcmlog}/wsgi.log",maxsize=2000000 From 5cf56a1d6fcf643ed8786663065b70e5891202b9 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Wed, 5 Feb 2020 14:23:27 +0300 Subject: [PATCH 41/85] ADCM-1050 has added fake validation#3 --- .../shared/configuration/main/main.component.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/web/src/app/shared/configuration/main/main.component.ts b/web/src/app/shared/configuration/main/main.component.ts index 1c87221466..c5ad95dee7 100644 --- a/web/src/app/shared/configuration/main/main.component.ts +++ b/web/src/app/shared/configuration/main/main.component.ts @@ -95,10 +95,7 @@ export class ConfigComponent extends SocketListener implements OnInit { fieldsEvents(e: { name: 'load'; data: { form: FormGroup } }) { if (e.name === 'load') { - setTimeout(_ => { - this.fields.checkForm(); - this.cdRef.detectChanges(); - }, 0); + this.stub(); } } @@ -112,7 +109,17 @@ export class ConfigComponent extends SocketListener implements OnInit { filter(c: { advanced: boolean; search: string }) { this.fields.dataOptions = this.service.filterApply(c); - this.fields.checkForm(); + this.stub(); + } + + /** + * change detection on manual + */ + stub() { + setTimeout(_ => { + this.fields.checkForm(); + this.cdRef.detectChanges(); + }, 0); } socketListener(m: EventMessage) { From 4d7d8037a95f8268b375b99a5bf2169bf73620da Mon Sep 17 00:00:00 2001 From: Anton Chevychalov Date: Wed, 5 Feb 2020 15:47:02 +0300 Subject: [PATCH 42/85] ADCM-1060 Tweak sys.path in conftest.py Pytest can't set path automaticly due to non standart layout of files in repo. So that commit set sys.path manually in relation to conftest.py position. --- tests/conftest.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index 2238eb49ed..e08d189778 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,4 +9,15 @@ # 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. +import os +import sys + + pytest_plugins = "adcm_pytest_plugin" + +# We have a number of calls from functional or ui_tests to cm module, +# so we need a way to extend PYTHONPATH at test time. +testdir = os.path.dirname(__file__) +rootdir = os.path.dirname(testdir) +pythondir = os.path.abspath(os.path.join(rootdir, 'python')) +sys.path.append(pythondir) From 8243f8c6ca6455c8c4ff04f9004efbac378d096e Mon Sep 17 00:00:00 2001 From: Konstantin Voschanov Date: Wed, 5 Feb 2020 17:04:34 +0300 Subject: [PATCH 43/85] ADCM-1121 fix scope in host context in inventory file --- python/cm/inventory.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/python/cm/inventory.py b/python/cm/inventory.py index 4e5ec91dbc..96481530c4 100644 --- a/python/cm/inventory.py +++ b/python/cm/inventory.py @@ -174,9 +174,10 @@ def get_provider_hosts(provider_id): def get_host(host_id): host = Host.objects.get(id=host_id) - groups = {'HOST': {'hosts': get_hosts([host])}} - groups.update(get_provider_hosts(host.provider.id)) - groups['PROVIDER']['vars'] = get_provider_config(host.provider.id) + groups = {'HOST': { + 'hosts': get_hosts([host]), + 'vars': get_provider_config(host.provider.id) + }} return groups From 1fb747659b4918cb9647a39de917b046a9f61d1c Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Wed, 5 Feb 2020 19:21:32 +0300 Subject: [PATCH 44/85] ADCM-1106 has add new component for scheme the configs --- .../configuration/fields/fields.component.ts | 2 +- .../scheme/scheme.component.html | 17 ++++++- .../configuration/scheme/scheme.component.ts | 44 +++++++++++++++++-- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/web/src/app/shared/configuration/fields/fields.component.ts b/web/src/app/shared/configuration/fields/fields.component.ts index a12d37869c..e650ae5dff 100644 --- a/web/src/app/shared/configuration/fields/fields.component.ts +++ b/web/src/app/shared/configuration/fields/fields.component.ts @@ -27,7 +27,7 @@ import { IConfig, PanelOptions, FieldOptions } from '../types'; - + diff --git a/web/src/app/shared/configuration/scheme/scheme.component.html b/web/src/app/shared/configuration/scheme/scheme.component.html index 8122f83b1d..922546aa6a 100644 --- a/web/src/app/shared/configuration/scheme/scheme.component.html +++ b/web/src/app/shared/configuration/scheme/scheme.component.html @@ -1 +1,16 @@ -
{{ options | json }}
+
+ + +
+
+ + + + + + {{ items | json}} + + +
\ No newline at end of file diff --git a/web/src/app/shared/configuration/scheme/scheme.component.ts b/web/src/app/shared/configuration/scheme/scheme.component.ts index 432d10abfc..3e45a672b0 100644 --- a/web/src/app/shared/configuration/scheme/scheme.component.ts +++ b/web/src/app/shared/configuration/scheme/scheme.component.ts @@ -12,7 +12,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; -import { FieldOptions } from '../types'; +import { IStructure } from '../types'; @Component({ selector: 'app-scheme', @@ -21,11 +21,49 @@ import { FieldOptions } from '../types'; }) export class SchemeComponent implements OnInit { @Input() form: FormGroup; - @Input() options: FieldOptions; + @Input() options: IStructure; + + value: any; + rules: Array; + + name: string; + type: string; + items: any[]; + + currentType: string; constructor() {} ngOnInit() { - + this.value = this.options.value; + + const current = this.options.rules; + this.currentType = this.options.rules.type; + + Object.keys(current).map(key => { + if (key === 'type') this.type = this.options.rules[key]; + else { + this.name = key; + this.rules = current[key]; + } + }); + + if (this.currentType === 'list') { + this.items = (this.options.value as Array).map(a => { + return { value: a, rules: this.rules }; + }); + } else if (this.currentType === 'dict') { + + this.items = Object.keys(this.value).map(b => { + const c = this.findRule(b); + return {value: this.value[b], rules: c}; + }); + } else { + + } + } + + findRule(key: string) { + return this.rules.find(a => a.name === key); } } From 977abdc1cee10cf810f1d1bbe318006a4671912c Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Wed, 5 Feb 2020 21:04:33 +0300 Subject: [PATCH 45/85] ADCM-1106 fixed to test --- .../app/shared/configuration/scheme/scheme.component.spec.ts | 4 +++- web/src/app/shared/configuration/scheme/scheme.component.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/web/src/app/shared/configuration/scheme/scheme.component.spec.ts b/web/src/app/shared/configuration/scheme/scheme.component.spec.ts index fdfafdd33d..65998bb167 100644 --- a/web/src/app/shared/configuration/scheme/scheme.component.spec.ts +++ b/web/src/app/shared/configuration/scheme/scheme.component.spec.ts @@ -12,6 +12,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { SchemeComponent } from './scheme.component'; +import { MaterialModule } from '@app/shared/material.module'; describe('SchemeComponent', () => { let component: SchemeComponent; @@ -19,6 +20,7 @@ describe('SchemeComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ + imports: [MaterialModule], declarations: [ SchemeComponent ] }) .compileComponents(); @@ -27,7 +29,7 @@ describe('SchemeComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(SchemeComponent); component = fixture.componentInstance; - fixture.detectChanges(); + //fixture.detectChanges(); }); it('should create', () => { diff --git a/web/src/app/shared/configuration/scheme/scheme.component.ts b/web/src/app/shared/configuration/scheme/scheme.component.ts index 3e45a672b0..6f16092e6e 100644 --- a/web/src/app/shared/configuration/scheme/scheme.component.ts +++ b/web/src/app/shared/configuration/scheme/scheme.component.ts @@ -64,6 +64,6 @@ export class SchemeComponent implements OnInit { } findRule(key: string) { - return this.rules.find(a => a.name === key); + return this.rules.find(a => a.name === key) || this.rules.find(a => Object.keys(a).find(k => k === key)); } } From 5aaef4925ca1fb07596d30a0cc01d521f5c094d8 Mon Sep 17 00:00:00 2001 From: Konstantin Voschanov Date: Wed, 5 Feb 2020 22:01:28 +0300 Subject: [PATCH 46/85] ADCM-1121 fix unit tests --- python/cm/tests_inventory.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/python/cm/tests_inventory.py b/python/cm/tests_inventory.py index 582f3655c6..8fec38ad39 100644 --- a/python/cm/tests_inventory.py +++ b/python/cm/tests_inventory.py @@ -174,9 +174,6 @@ def test_get_host(self, mock_get_hosts, mock_get_provider_hosts): groups = cm.inventory.get_host(host.id) test_groups = { 'HOST': { - 'hosts': [] - }, - 'PROVIDER': { 'hosts': [], 'vars': { 'provider': { @@ -190,7 +187,6 @@ def test_get_host(self, mock_get_hosts, mock_get_provider_hosts): } self.assertDictEqual(groups, test_groups) mock_get_hosts.assert_called_once_with([host]) - mock_get_provider_hosts.assert_called_once_with(host.provider.id) @patch('json.dump') @patch('cm.inventory.open') @@ -233,13 +229,6 @@ def test_prepare_job_inventory(self, mock_open, mock_dump): 'all': { 'children': { 'HOST': { - 'hosts': { - '': { - 'adcm_hostid': 1 - } - } - }, - 'PROVIDER': { 'hosts': { '': { 'adcm_hostid': 1 From 09e4bf10bd0da8f42c81084f14b46d9aae626e37 Mon Sep 17 00:00:00 2001 From: Mikhail Samoylov Date: Wed, 5 Feb 2020 22:53:49 +0300 Subject: [PATCH 47/85] Test import with strict version in import. Add descriptions for tests. --- tests/functional/test_upgrade_cluster.py | 23 ++++++++ .../test_upgrade_cluster_imports.py | 44 ++++++++++++-- .../config.yaml | 57 +++++++++++++++++++ 3 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/config.yaml diff --git a/tests/functional/test_upgrade_cluster.py b/tests/functional/test_upgrade_cluster.py index f8792826c2..3edad5f202 100644 --- a/tests/functional/test_upgrade_cluster.py +++ b/tests/functional/test_upgrade_cluster.py @@ -19,6 +19,29 @@ from tests.library.errorcodes import UPGRADE_ERROR +def test_upgrade_with_two_clusters(sdk_client_fs: ADCMClient): + """Upgrade cluster when we have two created clusters from one bundle + Scenario: + 1. Create two clusters from one bundle + 2. Upload upgradable bundle + 3. Upgrade first cluster + 4. Check that only first cluster was upgraded + """ + bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'cluster')) + sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgradable_cluster')) + cluster_first = bundle.cluster_create("test") + cluster_second = bundle.cluster_create("test2") + service = cluster_first.service_add(name="zookeeper") + upgr_cl = cluster_first.upgrade(name='upgrade to 1.6') + upgr_cl.do() + cluster_first.reread() + service.reread() + cluster_second.reread() + assert cluster_first.prototype().version == '1.6' + assert service.prototype().version == '3.4.11' + assert cluster_second.prototype().version == '1.5' + + def test_check_prototype(sdk_client_fs: ADCMClient): """Check prototype for service and cluster after upgrade :param sdk_client_fs: diff --git a/tests/functional/test_upgrade_cluster_imports.py b/tests/functional/test_upgrade_cluster_imports.py index a2ba15a7a4..d0278546bc 100644 --- a/tests/functional/test_upgrade_cluster_imports.py +++ b/tests/functional/test_upgrade_cluster_imports.py @@ -77,11 +77,41 @@ def test_upgrade_cluster_with_export(sdk_client_fs: ADCMClient): assert cluster_import.prototype_id != id_before +def test_incorrect_import_strcit_version(sdk_client_fs: ADCMClient): + """Upgrade cluster with service incorrect strict version + Scenario: + 1. Create cluster for upgrade with exports + 2. Create upgradable cluster with import and incorrect strict version + 3. Create service + 4. Import service from cluster with export to cluster from step 2 (with import) + 4. Upgrade cluster from step 1 + 5. Check that cluster was not upgraded because incorrect version for service + in cluster with import + """ + bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgrade_cluster_with_export')) + bundle_import = sdk_client_fs.upload_from_fs(get_data_dir( + __file__, 'upgradable_cluster_with_strict_incorrect_version')) + cluster = bundle.cluster_create("test") + service = cluster.service_add(name="hadoop") + cluster_import = bundle_import.cluster_create("cluster_import") + cluster_import.bind(service) + cluster_import.bind(cluster) + upgr = cluster.upgrade(name='upgrade to 1.6') + with pytest.raises(coreapi.exceptions.ErrorMessage) as e: + upgr.do() + err.UPGRADE_ERROR.equal(e) + + def test_incorrect_import_version(sdk_client_fs: ADCMClient): """Upgrade cluster with service incorrect version - - :param sdk_client_fs: - :return: + Scenario: + 1. Create cluster for upgrade with exports + 2. Create upgradable cluster with import and incorrect version + 3. Create service + 4. Import service from cluster with export to cluster from step 2 (with import) + 4. Upgrade cluster from step 1 + 5. Check that cluster was not upgraded because incorrect version for service + in cluster with import """ bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgrade_cluster_with_export')) bundle_import = sdk_client_fs.upload_from_fs(get_data_dir( @@ -98,8 +128,14 @@ def test_incorrect_import_version(sdk_client_fs: ADCMClient): def test_upgrade_cluster_without_service_config_in_import(sdk_client_fs: ADCMClient): - """Upgrade cluster with service when in new cluster + """Upgrade cluster with service when in new cluster when we haven't some service configuration variables + Scenario: + 1. Create cluster for upgrade with export + 2. Create upgradable cluster with import and without config in import + 3. Bind service from cluster with export to cluster with import + 4. Upgrade cluster with export + 5. Check upgrade error """ bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgrade_cluster_with_export')) bundle_import = sdk_client_fs.upload_from_fs(get_data_dir( diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/config.yaml new file mode 100644 index 0000000000..86e270d4a1 --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/config.yaml @@ -0,0 +1,57 @@ +# 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. +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min_strict: 2.1 + max_strict: 2.5 + ADH: + versions: + min_strict: 2.1 + max_strict: 4.0 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 From 76aad87487ffa6c66272b252841a67826f00b4ee Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Thu, 6 Feb 2020 12:41:00 +0300 Subject: [PATCH 48/85] ADCM-1106 fix to classs for test --- web/src/app/shared/configuration/fields/fields.component.ts | 2 +- web/src/app/shared/configuration/scheme/scheme.component.html | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/web/src/app/shared/configuration/fields/fields.component.ts b/web/src/app/shared/configuration/fields/fields.component.ts index e650ae5dff..a12d37869c 100644 --- a/web/src/app/shared/configuration/fields/fields.component.ts +++ b/web/src/app/shared/configuration/fields/fields.component.ts @@ -27,7 +27,7 @@ import { IConfig, PanelOptions, FieldOptions } from '../types'; - + diff --git a/web/src/app/shared/configuration/scheme/scheme.component.html b/web/src/app/shared/configuration/scheme/scheme.component.html index 922546aa6a..9420849676 100644 --- a/web/src/app/shared/configuration/scheme/scheme.component.html +++ b/web/src/app/shared/configuration/scheme/scheme.component.html @@ -10,7 +10,9 @@ - {{ items | json}} + +
{{ item | json }}
+
\ No newline at end of file From f8487bfbf2909a59014d3b8b564d00dd4dd19154 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Thu, 6 Feb 2020 14:03:21 +0300 Subject: [PATCH 49/85] ADCM-1065 check for upgradable on create bundle --- web/src/app/shared/components/issue-info.component.ts | 2 +- .../app/shared/components/list/base-list.directive.ts | 10 ++++++---- web/src/app/shared/details/detail.component.ts | 5 +++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/web/src/app/shared/components/issue-info.component.ts b/web/src/app/shared/components/issue-info.component.ts index d777996e1b..63b3c6afa0 100644 --- a/web/src/app/shared/components/issue-info.component.ts +++ b/web/src/app/shared/components/issue-info.component.ts @@ -65,7 +65,7 @@ export class IssueInfoComponent implements OnInit { getParent() { if (this.parent && this.parent.cluster_id !== this.current.id) { return `${this.parent.typeName}/${this.parent.id}/${this.typeName}`; - } else return this.typeName; + } else return this.typeName.split(';')[0]; } isArray(issue: [] | false): boolean { diff --git a/web/src/app/shared/components/list/base-list.directive.ts b/web/src/app/shared/components/list/base-list.directive.ts index b5d949baa5..f4367fd271 100644 --- a/web/src/app/shared/components/list/base-list.directive.ts +++ b/web/src/app/shared/components/list/base-list.directive.ts @@ -85,10 +85,12 @@ export class BaseListDirective extends SocketListener implements OnInit, OnDestr } socketListener(m: EventMessage): void { - // if (this.typeName === 'job' && m.object.type === 'job' && m.event === 'change_job_status' && m.object.details.type === 'status') { - // if (m.object.details.value === 'created' || m.object.details.value === 'success') this.refresh(); - // return; - // } + + /** check upgradable */ + if (m.event === 'create' && m.object.type === 'bundle' && this.typeName === 'cluster') { + this.refresh(m.object.id); + return; + } if (m.event === 'clear_issue' || m.event === 'raise_issue') return; diff --git a/web/src/app/shared/details/detail.component.ts b/web/src/app/shared/details/detail.component.ts index 42bfa3da5b..2e550a2a9b 100644 --- a/web/src/app/shared/details/detail.component.ts +++ b/web/src/app/shared/details/detail.component.ts @@ -69,8 +69,9 @@ export class DetailComponent extends SocketListener implements OnInit, OnDestroy } socketListener(m: EventMessage) { - if (m.event === 'create' && this.current.Current && m.object.type === 'cluster' && this.current.Current.typeName === 'cluster') { - // check the upgradable prop + + + if (m.event === 'create' && m.object.type === 'bundle') { this.model$ = this.current.reset(); } From 08c1736b42d1ae2efa7aa57826e04a89adc08969 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Thu, 6 Feb 2020 15:06:34 +0300 Subject: [PATCH 50/85] ADCM-1062 hide the overflow the long name for hosts --- web/src/app/shared/components/list/list.component.html | 2 +- web/src/app/shared/components/list/list.component.scss | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/web/src/app/shared/components/list/list.component.html b/web/src/app/shared/components/list/list.component.html index d711e6dec1..42368ece49 100644 --- a/web/src/app/shared/components/list/list.component.html +++ b/web/src/app/shared/components/list/list.component.html @@ -219,7 +219,7 @@ FQDN - {{ row.fqdn }} + {{ row.fqdn }} diff --git a/web/src/app/shared/components/list/list.component.scss b/web/src/app/shared/components/list/list.component.scss index d105b6efbf..5858d9b919 100644 --- a/web/src/app/shared/components/list/list.component.scss +++ b/web/src/app/shared/components/list/list.component.scss @@ -14,4 +14,8 @@ mat-header-cell.control, mat-cell.control { flex-basis: 60px; +} + +.overflow { + overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-right: 10px; } \ No newline at end of file From 1acfa49366469a4ad6cc49f4d79f1c7a11d2d57f Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Thu, 6 Feb 2020 17:32:23 +0300 Subject: [PATCH 51/85] ADCM-786 fixed the arrow 'Cluster' column for sorting --- web/src/app/shared/directives/multi-sort.directive.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/app/shared/directives/multi-sort.directive.ts b/web/src/app/shared/directives/multi-sort.directive.ts index 37e6c61973..da0f5d6b45 100644 --- a/web/src/app/shared/directives/multi-sort.directive.ts +++ b/web/src/app/shared/directives/multi-sort.directive.ts @@ -25,7 +25,7 @@ export class MultiSortDirective { param.split(',').forEach(cell => { const direction = cell[0] === '-' ? 'descending' : 'ascending', active = cell[0] === '-' ? cell.substr(1) : cell; - const c = el.querySelector(`mat-header-cell.mat-column-${active}`); + const c = el.querySelector(`mat-header-cell.mat-column-${active}`) || el.querySelector(`mat-header-cell[mat-sort-header="${active}"]`); if (c) { this.renderer.setAttribute(c, 'aria-sort', direction); const cont = c.querySelector('div.mat-sort-header-container'); @@ -45,7 +45,7 @@ export class MultiSortDirective { } } }); - }, 500); + }, 100); } constructor(private el: ElementRef, private renderer: Renderer2) {} From 7384b9646ebccae546512c05f80edd7065c01440 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Thu, 6 Feb 2020 17:39:40 +0300 Subject: [PATCH 52/85] fixed the tooltip's error navigation --- web/src/app/shared/components/issue-info.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/app/shared/components/issue-info.component.ts b/web/src/app/shared/components/issue-info.component.ts index d777996e1b..0a78180113 100644 --- a/web/src/app/shared/components/issue-info.component.ts +++ b/web/src/app/shared/components/issue-info.component.ts @@ -64,7 +64,7 @@ export class IssueInfoComponent implements OnInit { getParent() { if (this.parent && this.parent.cluster_id !== this.current.id) { - return `${this.parent.typeName}/${this.parent.id}/${this.typeName}`; + return `${this.parent.typeName.split(';')[0]}/${this.parent.id}/${this.typeName}`; } else return this.typeName; } From 55432503c71364f34482874f25ece915031d5ad1 Mon Sep 17 00:00:00 2001 From: Konstantin Voschanov Date: Thu, 6 Feb 2020 18:17:07 +0300 Subject: [PATCH 53/85] ADCM-1072 add adcm_delete_service ansible plugin --- .../plugins/action/adcm_delete_service.py | 66 +++++++++++++++++++ python/cm/api.py | 20 ++++++ python/cm/job.py | 13 ++-- 3 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 python/ansible/plugins/action/adcm_delete_service.py diff --git a/python/ansible/plugins/action/adcm_delete_service.py b/python/ansible/plugins/action/adcm_delete_service.py new file mode 100644 index 0000000000..68854e8019 --- /dev/null +++ b/python/ansible/plugins/action/adcm_delete_service.py @@ -0,0 +1,66 @@ +#!/usr/bin/python +# 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. + +# pylint: disable=wrong-import-position,unused-import + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +ANSIBLE_METADATA = {'metadata_version': '1.1', 'supported_by': 'Arenadata'} + +DOCUMENTATION = r''' +--- +module: adcm_delete_service +short_description: delete service from cluster in ADCM DB +description: + - The C(adcm_delete_service) module is intended to delete service from ADCM DB. + This module should be run in service context. Service Id is taken from context. +options: +''' + +EXAMPLES = r''' + - name: delete service from cluster + adcm_delete_service: +''' + +RETURN = r''' +''' + +import sys +from ansible.errors import AnsibleError +from ansible.plugins.action import ActionBase + +sys.path.append('/adcm/python') +import adcm.init_django +import cm.api +from cm.ansible_plugin import get_context_id +from cm.errors import AdcmEx +from cm.logger import log + + +class ActionModule(ActionBase): + + TRANSFERS_FILES = False + _VALID_ARGS = frozenset(()) + + def run(self, tmp=None, task_vars=None): + msg = 'You can delete service only in service context' + service_id = get_context_id(task_vars, 'service', 'service_id', msg) + log.info('ansible module adcm_delete_service: service #%s', service_id) + + try: + cm.api.delete_service_by_id(service_id) + except AdcmEx as e: + raise AnsibleError(e.code + ":" + e.msg) + + return {"failed": False, "changed": True} diff --git a/python/cm/api.py b/python/cm/api.py index b705bd86e3..eb347d2889 100644 --- a/python/cm/api.py +++ b/python/cm/api.py @@ -139,6 +139,11 @@ def delete_host(host): def delete_host_by_id(host_id): + """ + Host deleting + + This is intended for use in adcm_delete_host ansible plugin + """ try: host = Host.objects.get(id=host_id) except Host.DoesNotExist: @@ -146,6 +151,21 @@ def delete_host_by_id(host_id): delete_host(host) +def delete_service_by_id(service_id): + """ + Unconditional removal of service from cluster + + This is intended for use in adcm_delete_service ansible plugin + """ + try: + service = ClusterObject.objects.get(id=service_id) + except ClusterObject.DoesNotExist: + err('SERVICE_NOT_FOUND', 'Service with id #{} is not found'.format(service_id)) + cm.status_api.post_event('delete', 'service', service.id) + service.delete() + cm.status_api.load_service_map() + + def delete_service(service): if HostComponent.objects.filter(cluster=service.cluster, service=service): err('SERVICE_CONFLICT', 'Service #{} has component(s) on host(s)'.format(service.id)) diff --git a/python/cm/job.py b/python/cm/job.py index 2a195464a4..46896cf503 100644 --- a/python/cm/job.py +++ b/python/cm/job.py @@ -634,13 +634,16 @@ def set_task_status(task, status): def get_task_obj(context, obj_id): - if context == 'service': - obj = ClusterObject.objects.get(id=obj_id) - elif context == 'host': + def get_obj_safe(model, obj_id): try: - obj = Host.objects.get(id=obj_id) - except Host.DoesNotExist: + return model.objects.get(id=obj_id) + except model.DoesNotExist: return None + + if context == 'service': + obj = get_obj_safe(ClusterObject, obj_id) + elif context == 'host': + obj = get_obj_safe(Host, obj_id) elif context == 'cluster': obj = Cluster.objects.get(id=obj_id) elif context == 'provider': From 8601b98e2c9e352abfa2fa2ea085863f64a57676 Mon Sep 17 00:00:00 2001 From: Konstantin Voschanov Date: Fri, 7 Feb 2020 12:27:37 +0300 Subject: [PATCH 54/85] ADCM-1060 fix path to adcm in ansible lookup plugins --- python/ansible/plugins/lookup/adcm_config.py | 2 +- python/ansible/plugins/lookup/adcm_state.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/ansible/plugins/lookup/adcm_config.py b/python/ansible/plugins/lookup/adcm_config.py index f89e6e44db..01d8f13025 100644 --- a/python/ansible/plugins/lookup/adcm_config.py +++ b/python/ansible/plugins/lookup/adcm_config.py @@ -23,7 +23,7 @@ from ansible.utils.display import Display # pylint: disable=ungrouped-imports display = Display() -sys.path.append('/adcm') +sys.path.append('/adcm/python') import adcm.init_django import cm.adcm_config from cm.logger import log diff --git a/python/ansible/plugins/lookup/adcm_state.py b/python/ansible/plugins/lookup/adcm_state.py index d082f52be9..c4aa34d164 100644 --- a/python/ansible/plugins/lookup/adcm_state.py +++ b/python/ansible/plugins/lookup/adcm_state.py @@ -23,7 +23,7 @@ display = Display() import sys -sys.path.append('/adcm') +sys.path.append('/adcm/python') import adcm.init_django import cm.api import cm.status_api From e8d2d28aad443bea74a65cdc911a6d266d414abd Mon Sep 17 00:00:00 2001 From: Alexandr Alferov Date: Fri, 7 Feb 2020 12:57:38 +0300 Subject: [PATCH 55/85] ADCM-1105 Renamed field name for service component serializer. --- python/api/cluster_serial.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/api/cluster_serial.py b/python/api/cluster_serial.py index 2560e2d3a8..fb80fe4a5a 100644 --- a/python/api/cluster_serial.py +++ b/python/api/cluster_serial.py @@ -423,7 +423,7 @@ def get_kwargs(self, obj): id = serializers.IntegerField(read_only=True) name = serializers.SerializerMethodField() - component_prototype_id = serializers.SerializerMethodField() + prototype_id = serializers.SerializerMethodField() display_name = serializers.SerializerMethodField() description = serializers.SerializerMethodField() url = MyUrlField(read_only=True, view_name='service-component-details') @@ -431,7 +431,7 @@ def get_kwargs(self, obj): def get_name(self, obj): return obj.component.name - def get_component_prototype_id(self, obj): + def get_prototype_id(self, obj): return obj.component.id def get_display_name(self, obj): From 1458678ce625d0a0e859619f248f57b5e424d9c1 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Fri, 7 Feb 2020 19:25:31 +0300 Subject: [PATCH 56/85] ADCM-1106 structure for configs draft #1 --- web/src/app/core/types/func.ts | 2 +- .../shared/configuration/YspecStructure.ts | 21 +-- .../app/shared/configuration/field.service.ts | 14 +- .../scheme/scheme.component.html | 14 +- .../scheme/scheme.component.scss | 4 + web/src/app/shared/configuration/types.ts | 2 +- .../configuration/yspec/yspec.service.spec.ts | 152 ++++++++++++++++-- .../configuration/yspec/yspec.service.ts | 23 ++- 8 files changed, 190 insertions(+), 42 deletions(-) diff --git a/web/src/app/core/types/func.ts b/web/src/app/core/types/func.ts index 7421ce8c1c..8d2fc51692 100644 --- a/web/src/app/core/types/func.ts +++ b/web/src/app/core/types/func.ts @@ -11,9 +11,9 @@ // limitations under the License. import { controlType } from '@app/shared/configuration/field.service'; import { ConfigResultTypes, ConfigValueTypes, FieldStack } from '@app/shared/configuration/types'; -import { matchType } from '@app/shared/configuration/YspecStructure'; import { InnerIssue, Issue } from './issue'; +import { matchType } from '@app/shared/configuration/yspec/yspec.service'; export function getPattern(name: string): RegExp { const fn = { diff --git a/web/src/app/shared/configuration/YspecStructure.ts b/web/src/app/shared/configuration/YspecStructure.ts index cc44ba032e..f4080b4dc5 100644 --- a/web/src/app/shared/configuration/YspecStructure.ts +++ b/web/src/app/shared/configuration/YspecStructure.ts @@ -11,25 +11,8 @@ // limitations under the License. import { getControlType, getPattern } from '@app/core/types'; -import { FieldOptions, PanelOptions, ConfigValueTypes } from './types'; - -export type simpleType = 'string' | 'integer' | 'float' | 'bool' | 'int' | 'one_of' | 'dict_key_selection'; -export type reqursionType = 'list' | 'dict'; -export type matchType = simpleType | reqursionType; - -interface Iroot { - match: matchType; - selector?: string; - variants?: { [key: string]: string }; - item?: string; - items?: { [key: string]: string }; - required_items?: string[]; - default_item?: string; -} - -export interface IYspec { - [key: string]: Iroot; -} +import { ConfigValueTypes, FieldOptions, PanelOptions } from './types'; +import { simpleType, reqursionType, IYspec } from './yspec/yspec.service'; class Field { private _options: Partial; diff --git a/web/src/app/shared/configuration/field.service.ts b/web/src/app/shared/configuration/field.service.ts index 30328a5cee..7161c7ad2b 100644 --- a/web/src/app/shared/configuration/field.service.ts +++ b/web/src/app/shared/configuration/field.service.ts @@ -13,9 +13,17 @@ import { Injectable } from '@angular/core'; import { AbstractControl, FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms'; import { getControlType, getPattern, isObject } from '@app/core/types'; -import { ConfigOptions, ConfigResultTypes, ConfigValueTypes, FieldOptions, FieldStack, IConfig, PanelOptions, IStructure } from './types'; -import { YspecStructure, matchType } from './YspecStructure'; -import { YspecService } from './yspec/yspec.service'; +import { + ConfigOptions, + ConfigResultTypes, + ConfigValueTypes, + FieldOptions, + FieldStack, + IConfig, + IStructure, + PanelOptions, +} from './types'; +import { YspecService, matchType } from './yspec/yspec.service'; export interface IToolsEvent { name: string; diff --git a/web/src/app/shared/configuration/scheme/scheme.component.html b/web/src/app/shared/configuration/scheme/scheme.component.html index 9420849676..cf4262a304 100644 --- a/web/src/app/shared/configuration/scheme/scheme.component.html +++ b/web/src/app/shared/configuration/scheme/scheme.component.html @@ -7,12 +7,18 @@
- +
+ +
- -
{{ item | json }}
-
+ + + {{ item.rules.name }} + + +
\ No newline at end of file diff --git a/web/src/app/shared/configuration/scheme/scheme.component.scss b/web/src/app/shared/configuration/scheme/scheme.component.scss index e69de29bb2..acaa731f58 100644 --- a/web/src/app/shared/configuration/scheme/scheme.component.scss +++ b/web/src/app/shared/configuration/scheme/scheme.component.scss @@ -0,0 +1,4 @@ +:host { + display: block; + margin-bottom: 10px; +} \ No newline at end of file diff --git a/web/src/app/shared/configuration/types.ts b/web/src/app/shared/configuration/types.ts index 6c9379df6b..00a926484a 100644 --- a/web/src/app/shared/configuration/types.ts +++ b/web/src/app/shared/configuration/types.ts @@ -9,7 +9,7 @@ // 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. -import { IYspec } from './YspecStructure'; +import { IYspec } from './yspec/yspec.service'; export type stateType = 'created' | 'locked'; diff --git a/web/src/app/shared/configuration/yspec/yspec.service.spec.ts b/web/src/app/shared/configuration/yspec/yspec.service.spec.ts index f7b7bc468e..56555be569 100644 --- a/web/src/app/shared/configuration/yspec/yspec.service.spec.ts +++ b/web/src/app/shared/configuration/yspec/yspec.service.spec.ts @@ -9,10 +9,10 @@ // 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. -import { YspecService, IField } from './yspec.service'; -import { IYspec } from '../YspecStructure'; import { getPattern } from '@app/core/types'; +import { IField, IYspec, YspecService } from './yspec.service'; + const simpleField: IField = { name: 'root', type: 'string', @@ -53,7 +53,7 @@ describe('YspecService', () => { expect(service.field({ path: ['root'], type: 'string' })).toEqual(simpleField); }); - xit('create List', () => { + it('simple List with Dict', () => { service.Root = { root: { match: 'list', item: 'country_code' }, country_code: { @@ -72,10 +72,11 @@ describe('YspecService', () => { }; const output = { - type: 'dict', - country_code: [ - { - country: { + type: 'list', + root: { + type: 'dict', + country_code: [ + { name: 'country', type: 'string', controlType: 'textbox', @@ -84,10 +85,8 @@ describe('YspecService', () => { required: false, pattern: null } - } - }, - { - code: { + }, + { name: 'code', type: 'integer', controlType: 'textbox', @@ -97,6 +96,137 @@ describe('YspecService', () => { pattern: getPattern('integer') } } + ] + } + }; + + const _out = service.build(); + //console.log(_out); + expect(_out).toEqual(output); + }); + + it('test build function :: dictionary with inner elements', () => { + service.Root = { + boolean: { match: 'bool' }, + string: { match: 'string' }, + integer: { match: 'int' }, + float: { match: 'float' }, + list: { match: 'list', item: 'string' }, + onemoredict: { match: 'dict', items: { key1: 'list', key2: 'the_dict' } }, + the_dict: { match: 'dict', items: { key1: 'boolean', key2: 'string', key3: 'integer', key4: 'float', key5: 'list' } }, + root: { + match: 'dict', + items: { key1: 'boolean', key2: 'string', key3: 'integer', key4: 'float', key5: 'list', key6: 'onemoredict' } + } + }; + + const output = { + type: 'dict', + root: [ + { + name: 'key1', + type: 'bool', + path: ['key1'], + controlType: 'boolean', + validator: { required: false, pattern: getPattern('boolean') } + }, + { + name: 'key2', + type: 'string', + path: ['key2'], + controlType: 'textbox', + validator: { required: false, pattern: getPattern('string') } + }, + { + name: 'key3', + type: 'int', + path: ['key3'], + controlType: 'textbox', + validator: { required: false, pattern: getPattern('int') } + }, + { + name: 'key4', + type: 'float', + path: ['key4'], + controlType: 'textbox', + validator: { required: false, pattern: getPattern('float') } + }, + { + type: 'list', + key5: { + name: 'string', + type: 'string', + path: ['key5', 'string'], + controlType: 'textbox', + validator: { + required: false, + pattern: getPattern('string') + } + } + }, + { + type: 'dict', + key6: [ + { + type: 'list', + key1: { + name: 'string', + type: 'string', + path: ['key6', 'key1', 'string'], + controlType: 'textbox', + validator: { + required: false, + pattern: getPattern('string') + } + } + }, + { + type: 'dict', + key2: [ + { + name: 'key1', + type: 'bool', + path: ['key6', 'key2', 'key1'], + controlType: 'boolean', + validator: { required: false, pattern: getPattern('boolean') } + }, + { + name: 'key2', + type: 'string', + path: ['key6', 'key2', 'key2'], + controlType: 'textbox', + validator: { required: false, pattern: getPattern('string') } + }, + { + name: 'key3', + type: 'int', + path: ['key6', 'key2', 'key3'], + controlType: 'textbox', + validator: { required: false, pattern: getPattern('int') } + }, + { + name: 'key4', + type: 'float', + path: ['key6', 'key2', 'key4'], + controlType: 'textbox', + validator: { required: false, pattern: getPattern('float') } + }, + { + type: 'list', + key5: { + name: 'string', + type: 'string', + path: ['key6', 'key2', 'key5', 'string'], + controlType: 'textbox', + validator: { + required: false, + pattern: getPattern('string') + } + } + } + ] + } + ] } ] }; diff --git a/web/src/app/shared/configuration/yspec/yspec.service.ts b/web/src/app/shared/configuration/yspec/yspec.service.ts index d0a3330f5c..9f9796871a 100644 --- a/web/src/app/shared/configuration/yspec/yspec.service.ts +++ b/web/src/app/shared/configuration/yspec/yspec.service.ts @@ -12,7 +12,24 @@ import { getControlType, getPattern, IRoot } from '@app/core/types'; import { controlType } from '../field.service'; -import { IYspec, simpleType } from '../YspecStructure'; + +export type simpleType = 'string' | 'integer' | 'float' | 'bool' | 'int' | 'one_of' | 'dict_key_selection'; +export type reqursionType = 'list' | 'dict'; +export type matchType = simpleType | reqursionType; + +interface Iroot { + match: matchType; + selector?: string; + variants?: { [key: string]: string }; + item?: string; + items?: { [key: string]: string }; + required_items?: string[]; + default_item?: string; +} + +export interface IYspec { + [key: string]: Iroot; +} export interface IField { name: string; @@ -78,12 +95,12 @@ export class YspecService { list(item: string, path: string[]): { [x: string]: any; type: string } { if (!this.Root[item]) throw new Error('Not itmem for list'); - const name = path.reverse()[0] || 'root'; + const name = [...path].reverse()[0] || 'root'; return { type: 'list', [name]: this.build(item, [...path, item]) }; } dict(items: IRoot, path: string[]): { [x: string]: any; type: string } { - const name = path.reverse()[0] || 'root'; + const name = [...path].reverse()[0] || 'root'; return { type: 'dict', [name]: Object.keys(items).map((item_name: string) => { From 6442b28ff4a4e219d97ce0cec660c6abb93c394d Mon Sep 17 00:00:00 2001 From: Mikhail Samoylov Date: Sat, 8 Feb 2020 11:45:21 +0300 Subject: [PATCH 57/85] Fix comments. Add tests parameterized tests for strict version. --- .../test_upgrade_cluster_imports.py | 15 ++- .../config_generator_import.py | 115 ++++++++++++++++ .../config_generator_strict_import.py | 123 ++++++++++++++++++ .../{ => cluster-greater}/config.yaml | 20 +-- .../cluster-less/config.yaml | 47 +++++++ .../service-greater/config.yaml | 47 +++++++ .../service-less/config.yaml | 47 +++++++ .../cluster-equal/config.yaml | 47 +++++++ .../cluster-greater-equal/config.yaml | 47 +++++++ .../cluster-greater/config.yaml | 47 +++++++ .../cluster-less-equal/config.yaml | 47 +++++++ .../cluster-less/config.yaml | 47 +++++++ .../{ => service-equal}/config.yaml | 16 +-- .../service-greater-equal/config.yaml | 47 +++++++ .../service-greater/config.yaml | 47 +++++++ .../service-less-equal/config.yaml | 47 +++++++ .../service-less/config.yaml | 47 +++++++ tests/functional/test_upgrade_hostprovider.py | 59 ++++++++- 18 files changed, 876 insertions(+), 36 deletions(-) create mode 100644 tests/functional/test_upgrade_cluster_imports_data/config_generator_import.py create mode 100644 tests/functional/test_upgrade_cluster_imports_data/config_generator_strict_import.py rename tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/{ => cluster-greater}/config.yaml (56%) create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-less/config.yaml create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-greater/config.yaml create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-less/config.yaml create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-equal/config.yaml create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-greater-equal/config.yaml create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-greater/config.yaml create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-less-equal/config.yaml create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-less/config.yaml rename tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/{ => service-equal}/config.yaml (59%) create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-greater-equal/config.yaml create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-greater/config.yaml create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-less-equal/config.yaml create mode 100644 tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-less/config.yaml diff --git a/tests/functional/test_upgrade_cluster_imports.py b/tests/functional/test_upgrade_cluster_imports.py index d0278546bc..b4b1f162e4 100644 --- a/tests/functional/test_upgrade_cluster_imports.py +++ b/tests/functional/test_upgrade_cluster_imports.py @@ -13,8 +13,9 @@ import coreapi import pytest + from adcm_client.objects import ADCMClient -from adcm_pytest_plugin.utils import get_data_dir +from adcm_pytest_plugin.utils import get_data_dir, parametrize_by_data_subdirs from tests.library import errorcodes as err @@ -77,7 +78,8 @@ def test_upgrade_cluster_with_export(sdk_client_fs: ADCMClient): assert cluster_import.prototype_id != id_before -def test_incorrect_import_strcit_version(sdk_client_fs: ADCMClient): +@parametrize_by_data_subdirs(__file__, "upgradable_cluster_with_strict_incorrect_version") +def test_incorrect_import_striсt_version(sdk_client_fs: ADCMClient, path): """Upgrade cluster with service incorrect strict version Scenario: 1. Create cluster for upgrade with exports @@ -89,8 +91,7 @@ def test_incorrect_import_strcit_version(sdk_client_fs: ADCMClient): in cluster with import """ bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgrade_cluster_with_export')) - bundle_import = sdk_client_fs.upload_from_fs(get_data_dir( - __file__, 'upgradable_cluster_with_strict_incorrect_version')) + bundle_import = sdk_client_fs.upload_from_fs(path) cluster = bundle.cluster_create("test") service = cluster.service_add(name="hadoop") cluster_import = bundle_import.cluster_create("cluster_import") @@ -102,7 +103,8 @@ def test_incorrect_import_strcit_version(sdk_client_fs: ADCMClient): err.UPGRADE_ERROR.equal(e) -def test_incorrect_import_version(sdk_client_fs: ADCMClient): +@parametrize_by_data_subdirs(__file__, "upgradable_cluster_with_incorrect_version") +def test_incorrect_import_version(sdk_client_fs: ADCMClient, path): """Upgrade cluster with service incorrect version Scenario: 1. Create cluster for upgrade with exports @@ -114,8 +116,7 @@ def test_incorrect_import_version(sdk_client_fs: ADCMClient): in cluster with import """ bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgrade_cluster_with_export')) - bundle_import = sdk_client_fs.upload_from_fs(get_data_dir( - __file__, 'upgradable_cluster_with_incorrect_version')) + bundle_import = sdk_client_fs.upload_from_fs(path) cluster = bundle.cluster_create("test") service = cluster.service_add(name="hadoop") cluster_import = bundle_import.cluster_create("cluster_import") diff --git a/tests/functional/test_upgrade_cluster_imports_data/config_generator_import.py b/tests/functional/test_upgrade_cluster_imports_data/config_generator_import.py new file mode 100644 index 0000000000..8dbd7e7617 --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/config_generator_import.py @@ -0,0 +1,115 @@ +import os + +SERVICE_VERSIONS = (('service-less', '2.2', '2.4'), ("service-greater", '1', '2')) + +CLUSTER_VERSIONS = (('cluster-less', '1.1', '2.4'), ("cluster-greater", '0.5', '0.9')) +TEMPLATE_SERVICE = """ +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min: {0} + max: {1} + ADH: + versions: + min_strict: 0.1 + max_strict: 4.0 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 +""" + +TEMPLATE_CLUSTER = """ +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min_strict: 1.5 + max_strict: 2.5 + ADH: + versions: + min_strict: {0} + max_strict: {1} + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 +""" + +for t in SERVICE_VERSIONS: + d_name = "upgradable_cluster_with_incorrect_version/{}".format(t[0]) + os.makedirs(d_name) + with open("{}/config.yaml".format(d_name), "w+") as f: + f.write(TEMPLATE_SERVICE.format(t[1], t[2])) + +for t in CLUSTER_VERSIONS: + d_name = "upgradable_cluster_with_incorrect_version/{}".format(t[0]) + os.makedirs(d_name) + with open("{}/config.yaml".format(d_name), "w+") as f: + f.write(TEMPLATE_CLUSTER.format(t[1], t[2])) + diff --git a/tests/functional/test_upgrade_cluster_imports_data/config_generator_strict_import.py b/tests/functional/test_upgrade_cluster_imports_data/config_generator_strict_import.py new file mode 100644 index 0000000000..a0fdbb809f --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/config_generator_strict_import.py @@ -0,0 +1,123 @@ +import os + +SERVICE_VERSIONS = (("service-less-equal", "2.1", "3.0"), + ("service-greater-equal", "1.5", "2.1"), + ("service-equal", "2.1", '2.1'), + ('service-less', '2.2', '2.4'), + ("service-greater", '1', '2')) + +CLUSTER_VERSIONS = (("cluster-less-equal", "1.0", "2.0"), + ("cluster-greater-equal", "0.9", "1.0"), + ("cluster-equal", "1.0", '1.0'), + ('cluster-less', '1.1', '2.4'), + ("cluster-greater", '0.5', '0.9')) +TEMPLATE_SERVICE = """ +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min_strict: {0} + max_strict: {1} + ADH: + versions: + min_strict: 0.1 + max_strict: 4.0 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 +""" + +TEMPLATE_CLUSTER = """ +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min_strict: 1.5 + max_strict: 2.5 + ADH: + versions: + min_strict: {0} + max_strict: {1} + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 +""" + +for t in SERVICE_VERSIONS: + d_name = "upgradable_cluster_with_strict_incorrect_version/{}".format(t[0]) + os.makedirs(d_name) + with open("{}/config.yaml".format(d_name), "w+") as f: + f.write(TEMPLATE_SERVICE.format(t[1], t[2])) + +for t in CLUSTER_VERSIONS: + d_name = "upgradable_cluster_with_strict_incorrect_version/{}".format(t[0]) + os.makedirs(d_name) + with open("{}/config.yaml".format(d_name), "w+") as f: + f.write(TEMPLATE_CLUSTER.format(t[1], t[2])) + diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-greater/config.yaml similarity index 56% rename from tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/config.yaml rename to tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-greater/config.yaml index b98152e0b3..3001ec1938 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-greater/config.yaml @@ -1,14 +1,4 @@ -# 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. + - type: cluster name: ADH @@ -33,12 +23,12 @@ import: hadoop: versions: - min: 2.3 - max: 2.5 + min_strict: 1.5 + max_strict: 2.5 ADH: versions: - min: 2.0 - max: 4.0 + min_strict: 0.5 + max_strict: 0.9 - type: service name: hadoop diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-less/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-less/config.yaml new file mode 100644 index 0000000000..9a086c7b33 --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-less/config.yaml @@ -0,0 +1,47 @@ + +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min_strict: 1.5 + max_strict: 2.5 + ADH: + versions: + min_strict: 1.1 + max_strict: 2.4 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-greater/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-greater/config.yaml new file mode 100644 index 0000000000..19d0bb09f3 --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-greater/config.yaml @@ -0,0 +1,47 @@ + +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min: 1 + max: 2 + ADH: + versions: + min_strict: 0.1 + max_strict: 4.0 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-less/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-less/config.yaml new file mode 100644 index 0000000000..020e666efa --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-less/config.yaml @@ -0,0 +1,47 @@ + +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min: 2.2 + max: 2.4 + ADH: + versions: + min_strict: 0.1 + max_strict: 4.0 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-equal/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-equal/config.yaml new file mode 100644 index 0000000000..43738cbd6a --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-equal/config.yaml @@ -0,0 +1,47 @@ + +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min_strict: 1.5 + max_strict: 2.5 + ADH: + versions: + min_strict: 1.0 + max_strict: 1.0 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-greater-equal/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-greater-equal/config.yaml new file mode 100644 index 0000000000..14ccdbe227 --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-greater-equal/config.yaml @@ -0,0 +1,47 @@ + +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min_strict: 1.5 + max_strict: 2.5 + ADH: + versions: + min_strict: 0.9 + max_strict: 1.0 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-greater/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-greater/config.yaml new file mode 100644 index 0000000000..3001ec1938 --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-greater/config.yaml @@ -0,0 +1,47 @@ + +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min_strict: 1.5 + max_strict: 2.5 + ADH: + versions: + min_strict: 0.5 + max_strict: 0.9 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-less-equal/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-less-equal/config.yaml new file mode 100644 index 0000000000..9b6354ffa4 --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-less-equal/config.yaml @@ -0,0 +1,47 @@ + +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min_strict: 1.5 + max_strict: 2.5 + ADH: + versions: + min_strict: 1.0 + max_strict: 2.0 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-less/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-less/config.yaml new file mode 100644 index 0000000000..9a086c7b33 --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-less/config.yaml @@ -0,0 +1,47 @@ + +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min_strict: 1.5 + max_strict: 2.5 + ADH: + versions: + min_strict: 1.1 + max_strict: 2.4 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-equal/config.yaml similarity index 59% rename from tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/config.yaml rename to tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-equal/config.yaml index 86e270d4a1..820ab4aedd 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-equal/config.yaml @@ -1,14 +1,4 @@ -# 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. + - type: cluster name: ADH @@ -34,10 +24,10 @@ hadoop: versions: min_strict: 2.1 - max_strict: 2.5 + max_strict: 2.1 ADH: versions: - min_strict: 2.1 + min_strict: 0.1 max_strict: 4.0 - type: service diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-greater-equal/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-greater-equal/config.yaml new file mode 100644 index 0000000000..59c82598f9 --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-greater-equal/config.yaml @@ -0,0 +1,47 @@ + +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min_strict: 1.5 + max_strict: 2.1 + ADH: + versions: + min_strict: 0.1 + max_strict: 4.0 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-greater/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-greater/config.yaml new file mode 100644 index 0000000000..093625f115 --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-greater/config.yaml @@ -0,0 +1,47 @@ + +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min_strict: 1 + max_strict: 2 + ADH: + versions: + min_strict: 0.1 + max_strict: 4.0 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-less-equal/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-less-equal/config.yaml new file mode 100644 index 0000000000..a78d4ef3be --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-less-equal/config.yaml @@ -0,0 +1,47 @@ + +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min_strict: 2.1 + max_strict: 3.0 + ADH: + versions: + min_strict: 0.1 + max_strict: 4.0 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-less/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-less/config.yaml new file mode 100644 index 0000000000..9e7b8c412c --- /dev/null +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-less/config.yaml @@ -0,0 +1,47 @@ + +- + type: cluster + name: ADH + version: 1.6 + upgrade: + - versions: + min: 0.4 + max: 1.5 + name: upgrade to 1.6 + description: New cool upgrade + states: + available: any + on_success: upgradable + - versions: + min: 1.0 + max: 1.8 + description: Super new upgrade + name: upgrade 2 + states: + available: [created, installed, upgradable] + on_success: upgradated + import: + hadoop: + versions: + min_strict: 2.2 + max_strict: 2.4 + ADH: + versions: + min_strict: 0.1 + max_strict: 4.0 + +- type: service + name: hadoop + version: 2.2 + + config: + core-site: + param1: + type: string + required: false + param2: + type: integer + required: false + quorum: + type: integer + default: 3 diff --git a/tests/functional/test_upgrade_hostprovider.py b/tests/functional/test_upgrade_hostprovider.py index c603dd2f3d..96ef31c2d2 100644 --- a/tests/functional/test_upgrade_hostprovider.py +++ b/tests/functional/test_upgrade_hostprovider.py @@ -19,8 +19,65 @@ from tests.library.errorcodes import UPGRADE_ERROR +def test_upgrade_with_two_hostproviders(sdk_client_fs: ADCMClient): + """Upgrade hostprovider when we have two created hostproviders with hosts from one bundle + Scenario: + 1. Create two hostproviders from one bundle + 2. Upload upgradable bundle + 3. Create host for each hostprovider + 4. Upgrade first hostprovider + 5. Check that only first hostprovider and hosts was upgraded + """ + bundle = sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'hostprovider')) + sdk_client_fs.upload_from_fs(get_data_dir(__file__, 'upgradable_hostprovider')) + hostprovider_first = bundle.provider_create("hp_first") + hostprovider_first_proto_before = hostprovider_first.prototype() + hostprovider_first_id_before = hostprovider_first.id + + hostprovider_second = bundle.provider_create("hp_second") + hostprovider_second_proto_before = hostprovider_second.prototype() + hostprovider_second_id_before = hostprovider_second.id + hp1_host1 = hostprovider_first.host_create(fqdn="localhost") + hp1_host1_id_before = hp1_host1.id + hp1_host1_proto_before = hp1_host1.prototype() + hp1_host2 = hostprovider_first.host_create(fqdn="localhost2") + hp1_host3 = hostprovider_first.host_create(fqdn="localhost3") + hp2_host1 = hostprovider_second.host_create(fqdn="hp2-localhost") + hp2_host1_proto_before = hp2_host1.prototype() + hp2_host1_id_before = hp2_host1.id + hp2_host2 = hostprovider_second.host_create(fqdn="hp2-localhost2") + hp2_host3 = hostprovider_second.host_create(fqdn="hp2-localhost3") + upgr = hostprovider_first.upgrade(name='upgrade to 2.0') + upgr.do() + hostprovider_first.reread() + hostprovider_second.reread() + hp1_host1.reread() + hp1_host2.reread() + hp1_host3.reread() + hp2_host1.reread() + hp2_host2.reread() + hp2_host3.reread() + hp_first_proto_after = hostprovider_first.prototype() + hp1_host_proto_after = hp1_host1.prototype() + hp_second_proto_after = hostprovider_second.prototype() + hp2_host1_proto_after = hp2_host1.prototype() + assert hostprovider_first.prototype().version == '2.0' + assert hp1_host1.prototype().version == '00.10' + assert hostprovider_second.prototype().version == '1.0' + assert hp2_host1.prototype().version == '00.09' + assert hostprovider_first_id_before == hostprovider_first.id + assert hp1_host1_id_before == hp1_host1.id + assert hostprovider_first_proto_before.id != hp_first_proto_after.id + assert hp1_host1_proto_before.id != hp1_host_proto_after.id + + assert hostprovider_second_id_before == hostprovider_second.id + assert hp2_host1_id_before == hp2_host1.id + assert hostprovider_second_proto_before.id == hp_second_proto_after.id + assert hp2_host1_proto_before.id == hp2_host1_proto_after.id + + def test_check_prototype(sdk_client_fs: ADCMClient): - """Check prototype for service and cluster after upgrade + """Check prototype for provider and host after upgrade :param sdk_client_fs: :return: """ From dd70db6002a8b835c9d3aae5cfeec4a3013aada7 Mon Sep 17 00:00:00 2001 From: Mikhail Samoylov Date: Sat, 8 Feb 2020 11:57:46 +0300 Subject: [PATCH 58/85] Skip too many local variables for test. --- tests/functional/test_upgrade_hostprovider.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/functional/test_upgrade_hostprovider.py b/tests/functional/test_upgrade_hostprovider.py index 96ef31c2d2..a74791800f 100644 --- a/tests/functional/test_upgrade_hostprovider.py +++ b/tests/functional/test_upgrade_hostprovider.py @@ -19,6 +19,7 @@ from tests.library.errorcodes import UPGRADE_ERROR +# pylint: disable=too-many-locals def test_upgrade_with_two_hostproviders(sdk_client_fs: ADCMClient): """Upgrade hostprovider when we have two created hostproviders with hosts from one bundle Scenario: From 8447f38e228cfbbdcab150d2b3f75d97a74f0a44 Mon Sep 17 00:00:00 2001 From: Mikhail Samoylov Date: Sat, 8 Feb 2020 12:29:37 +0300 Subject: [PATCH 59/85] Linter fix. --- .../test_upgrade_cluster_imports_data/config_generator_import.py | 1 - .../config_generator_strict_import.py | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/functional/test_upgrade_cluster_imports_data/config_generator_import.py b/tests/functional/test_upgrade_cluster_imports_data/config_generator_import.py index 8dbd7e7617..baf44f4aba 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/config_generator_import.py +++ b/tests/functional/test_upgrade_cluster_imports_data/config_generator_import.py @@ -112,4 +112,3 @@ os.makedirs(d_name) with open("{}/config.yaml".format(d_name), "w+") as f: f.write(TEMPLATE_CLUSTER.format(t[1], t[2])) - diff --git a/tests/functional/test_upgrade_cluster_imports_data/config_generator_strict_import.py b/tests/functional/test_upgrade_cluster_imports_data/config_generator_strict_import.py index a0fdbb809f..fe8b07c8d4 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/config_generator_strict_import.py +++ b/tests/functional/test_upgrade_cluster_imports_data/config_generator_strict_import.py @@ -120,4 +120,3 @@ os.makedirs(d_name) with open("{}/config.yaml".format(d_name), "w+") as f: f.write(TEMPLATE_CLUSTER.format(t[1], t[2])) - From 7d355317baa9082ce4064f8b521bfd427b7a9a58 Mon Sep 17 00:00:00 2001 From: Mikhail Samoylov Date: Mon, 10 Feb 2020 10:22:47 +0300 Subject: [PATCH 60/85] Change strict to not strict import. --- .../config_generator_import.py | 12 ++++++------ .../cluster-greater/config.yaml | 8 ++++---- .../cluster-less/config.yaml | 8 ++++---- .../service-greater/config.yaml | 4 ++-- .../service-less/config.yaml | 4 ++-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/functional/test_upgrade_cluster_imports_data/config_generator_import.py b/tests/functional/test_upgrade_cluster_imports_data/config_generator_import.py index baf44f4aba..d5d021faff 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/config_generator_import.py +++ b/tests/functional/test_upgrade_cluster_imports_data/config_generator_import.py @@ -32,8 +32,8 @@ max: {1} ADH: versions: - min_strict: 0.1 - max_strict: 4.0 + min: 0.1 + max: 4.0 - type: service name: hadoop @@ -77,12 +77,12 @@ import: hadoop: versions: - min_strict: 1.5 - max_strict: 2.5 + min: 1.5 + max: 2.5 ADH: versions: - min_strict: {0} - max_strict: {1} + min: {0} + max: {1} - type: service name: hadoop diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-greater/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-greater/config.yaml index 3001ec1938..31d21f6a0d 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-greater/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-greater/config.yaml @@ -23,12 +23,12 @@ import: hadoop: versions: - min_strict: 1.5 - max_strict: 2.5 + min: 1.5 + max: 2.5 ADH: versions: - min_strict: 0.5 - max_strict: 0.9 + min: 0.5 + max: 0.9 - type: service name: hadoop diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-less/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-less/config.yaml index 9a086c7b33..ed8054d782 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-less/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-less/config.yaml @@ -23,12 +23,12 @@ import: hadoop: versions: - min_strict: 1.5 - max_strict: 2.5 + min: 1.5 + max: 2.5 ADH: versions: - min_strict: 1.1 - max_strict: 2.4 + min: 1.1 + max: 2.4 - type: service name: hadoop diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-greater/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-greater/config.yaml index 19d0bb09f3..cc145b14b9 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-greater/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-greater/config.yaml @@ -27,8 +27,8 @@ max: 2 ADH: versions: - min_strict: 0.1 - max_strict: 4.0 + min: 0.1 + max: 4.0 - type: service name: hadoop diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-less/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-less/config.yaml index 020e666efa..142e13d02d 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-less/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-less/config.yaml @@ -27,8 +27,8 @@ max: 2.4 ADH: versions: - min_strict: 0.1 - max_strict: 4.0 + min: 0.1 + max: 4.0 - type: service name: hadoop From 3e9fc155976cbefd3311376cee7a14a081df5f79 Mon Sep 17 00:00:00 2001 From: Mikhail Samoylov Date: Mon, 10 Feb 2020 10:35:34 +0300 Subject: [PATCH 61/85] Fix logic in tests for strict and not strict import versions. --- .../config_generator_import.py | 4 ++-- .../config_generator_strict_import.py | 16 ++++++++-------- .../cluster-less/config.yaml | 2 +- .../service-less/config.yaml | 2 +- .../cluster-equal/config.yaml | 4 ++-- .../cluster-greater-equal/config.yaml | 2 +- .../cluster-less-equal/config.yaml | 2 +- .../cluster-less/config.yaml | 2 +- .../service-equal/config.yaml | 4 ++-- .../service-greater-equal/config.yaml | 2 +- .../service-less-equal/config.yaml | 2 +- .../service-less/config.yaml | 2 +- 12 files changed, 22 insertions(+), 22 deletions(-) diff --git a/tests/functional/test_upgrade_cluster_imports_data/config_generator_import.py b/tests/functional/test_upgrade_cluster_imports_data/config_generator_import.py index d5d021faff..a35bb8a34d 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/config_generator_import.py +++ b/tests/functional/test_upgrade_cluster_imports_data/config_generator_import.py @@ -1,8 +1,8 @@ import os -SERVICE_VERSIONS = (('service-less', '2.2', '2.4'), ("service-greater", '1', '2')) +SERVICE_VERSIONS = (('service-less', '2.3', '2.4'), ("service-greater", '1', '2')) -CLUSTER_VERSIONS = (('cluster-less', '1.1', '2.4'), ("cluster-greater", '0.5', '0.9')) +CLUSTER_VERSIONS = (('cluster-less', '1.7', '2.4'), ("cluster-greater", '0.5', '0.9')) TEMPLATE_SERVICE = """ - type: cluster diff --git a/tests/functional/test_upgrade_cluster_imports_data/config_generator_strict_import.py b/tests/functional/test_upgrade_cluster_imports_data/config_generator_strict_import.py index fe8b07c8d4..625be2332b 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/config_generator_strict_import.py +++ b/tests/functional/test_upgrade_cluster_imports_data/config_generator_strict_import.py @@ -1,15 +1,15 @@ import os -SERVICE_VERSIONS = (("service-less-equal", "2.1", "3.0"), - ("service-greater-equal", "1.5", "2.1"), - ("service-equal", "2.1", '2.1'), - ('service-less', '2.2', '2.4'), +SERVICE_VERSIONS = (("service-less-equal", "2.2", "3.0"), + ("service-greater-equal", "1.5", "2.2"), + ("service-equal", "2.2", '2.2'), + ('service-less', '2.3', '2.4'), ("service-greater", '1', '2')) -CLUSTER_VERSIONS = (("cluster-less-equal", "1.0", "2.0"), - ("cluster-greater-equal", "0.9", "1.0"), - ("cluster-equal", "1.0", '1.0'), - ('cluster-less', '1.1', '2.4'), +CLUSTER_VERSIONS = (("cluster-less-equal", "1.6", "2.0"), + ("cluster-greater-equal", "0.9", "1.6"), + ("cluster-equal", "1.6", '1.6'), + ('cluster-less', '1.7', '2.4'), ("cluster-greater", '0.5', '0.9')) TEMPLATE_SERVICE = """ - diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-less/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-less/config.yaml index ed8054d782..e942b949b9 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-less/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/cluster-less/config.yaml @@ -27,7 +27,7 @@ max: 2.5 ADH: versions: - min: 1.1 + min: 1.7 max: 2.4 - type: service diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-less/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-less/config.yaml index 142e13d02d..ff485db112 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-less/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_incorrect_version/service-less/config.yaml @@ -23,7 +23,7 @@ import: hadoop: versions: - min: 2.2 + min: 2.3 max: 2.4 ADH: versions: diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-equal/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-equal/config.yaml index 43738cbd6a..a3a010746e 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-equal/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-equal/config.yaml @@ -27,8 +27,8 @@ max_strict: 2.5 ADH: versions: - min_strict: 1.0 - max_strict: 1.0 + min_strict: 1.6 + max_strict: 1.6 - type: service name: hadoop diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-greater-equal/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-greater-equal/config.yaml index 14ccdbe227..eda0de0fa6 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-greater-equal/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-greater-equal/config.yaml @@ -28,7 +28,7 @@ ADH: versions: min_strict: 0.9 - max_strict: 1.0 + max_strict: 1.6 - type: service name: hadoop diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-less-equal/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-less-equal/config.yaml index 9b6354ffa4..fcef1a88c8 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-less-equal/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-less-equal/config.yaml @@ -27,7 +27,7 @@ max_strict: 2.5 ADH: versions: - min_strict: 1.0 + min_strict: 1.6 max_strict: 2.0 - type: service diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-less/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-less/config.yaml index 9a086c7b33..26f5937b4f 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-less/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/cluster-less/config.yaml @@ -27,7 +27,7 @@ max_strict: 2.5 ADH: versions: - min_strict: 1.1 + min_strict: 1.7 max_strict: 2.4 - type: service diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-equal/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-equal/config.yaml index 820ab4aedd..4449c6e97b 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-equal/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-equal/config.yaml @@ -23,8 +23,8 @@ import: hadoop: versions: - min_strict: 2.1 - max_strict: 2.1 + min_strict: 2.2 + max_strict: 2.2 ADH: versions: min_strict: 0.1 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-greater-equal/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-greater-equal/config.yaml index 59c82598f9..8b98108150 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-greater-equal/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-greater-equal/config.yaml @@ -24,7 +24,7 @@ hadoop: versions: min_strict: 1.5 - max_strict: 2.1 + max_strict: 2.2 ADH: versions: min_strict: 0.1 diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-less-equal/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-less-equal/config.yaml index a78d4ef3be..b56423c875 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-less-equal/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-less-equal/config.yaml @@ -23,7 +23,7 @@ import: hadoop: versions: - min_strict: 2.1 + min_strict: 2.2 max_strict: 3.0 ADH: versions: diff --git a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-less/config.yaml b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-less/config.yaml index 9e7b8c412c..cba198a38f 100644 --- a/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-less/config.yaml +++ b/tests/functional/test_upgrade_cluster_imports_data/upgradable_cluster_with_strict_incorrect_version/service-less/config.yaml @@ -23,7 +23,7 @@ import: hadoop: versions: - min_strict: 2.2 + min_strict: 2.3 max_strict: 2.4 ADH: versions: From 6e62b1d8910e38dd2faa8d800d13076e233f9b0b Mon Sep 17 00:00:00 2001 From: Mikhail Samoylov Date: Mon, 10 Feb 2020 10:42:09 +0300 Subject: [PATCH 62/85] Change versions from integer to string in hostprovider configs. --- .../test_upgrade_hostprovider_data/hostprovider/config.yaml | 6 +++--- .../upgradable_hostprovider/config.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/functional/test_upgrade_hostprovider_data/hostprovider/config.yaml b/tests/functional/test_upgrade_hostprovider_data/hostprovider/config.yaml index 1bc01f2ec6..2fed33c993 100644 --- a/tests/functional/test_upgrade_hostprovider_data/hostprovider/config.yaml +++ b/tests/functional/test_upgrade_hostprovider_data/hostprovider/config.yaml @@ -14,7 +14,7 @@ type: provider name: sample hostprovider - version: 1.0 + version: '1.0' config: required: type: integer @@ -42,7 +42,7 @@ - type: host name: vHost - version: 00.09 + version: '00.09' config: str_param: @@ -54,4 +54,4 @@ type: integer required: false default: 2 - description: must be changed to 5 \ No newline at end of file + description: must be changed to 5 diff --git a/tests/functional/test_upgrade_hostprovider_data/upgradable_hostprovider/config.yaml b/tests/functional/test_upgrade_hostprovider_data/upgradable_hostprovider/config.yaml index 28dccb41c5..bee71b995f 100644 --- a/tests/functional/test_upgrade_hostprovider_data/upgradable_hostprovider/config.yaml +++ b/tests/functional/test_upgrade_hostprovider_data/upgradable_hostprovider/config.yaml @@ -14,7 +14,7 @@ type: provider name: sample hostprovider - version: 2.0 + version: '2.0' upgrade: - versions: From 1347ab4e1cccad2f2dbc433c5ceb772404f53e2d Mon Sep 17 00:00:00 2001 From: Mikhail Samoylov Date: Mon, 10 Feb 2020 14:37:40 +0300 Subject: [PATCH 63/85] Fix ASCII symbol in test name. --- tests/functional/test_upgrade_cluster_imports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/test_upgrade_cluster_imports.py b/tests/functional/test_upgrade_cluster_imports.py index b4b1f162e4..ccdd60572b 100644 --- a/tests/functional/test_upgrade_cluster_imports.py +++ b/tests/functional/test_upgrade_cluster_imports.py @@ -79,7 +79,7 @@ def test_upgrade_cluster_with_export(sdk_client_fs: ADCMClient): @parametrize_by_data_subdirs(__file__, "upgradable_cluster_with_strict_incorrect_version") -def test_incorrect_import_striсt_version(sdk_client_fs: ADCMClient, path): +def test_incorrect_import_strict_version(sdk_client_fs: ADCMClient, path): """Upgrade cluster with service incorrect strict version Scenario: 1. Create cluster for upgrade with exports From d1596e8be4883ec454aeb6ed97b4fdcbdb47625d Mon Sep 17 00:00:00 2001 From: Konstantin Voschanov Date: Mon, 10 Feb 2020 14:47:15 +0300 Subject: [PATCH 64/85] ADCM-1111 add license_url to upgrade list in api --- python/api/serializers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/api/serializers.py b/python/api/serializers.py index db7363b7ee..f6bd28e1a9 100644 --- a/python/api/serializers.py +++ b/python/api/serializers.py @@ -629,6 +629,7 @@ class ProviderActionShort(ActionShort): class UpgradeSerializer(serializers.Serializer): id = serializers.IntegerField(read_only=True) name = serializers.CharField(required=False) + bundle_id = serializers.IntegerField(read_only=True) description = serializers.CharField(required=False) min_version = serializers.CharField(required=False) max_version = serializers.CharField(required=False) @@ -636,6 +637,7 @@ class UpgradeSerializer(serializers.Serializer): max_strict = serializers.BooleanField(required=False) upgradable = serializers.BooleanField(required=False) license = serializers.CharField(required=False) + license_url = hlink('bundle-license', 'bundle_id', 'bundle_id') from_edition = JSONField(required=False) state_available = JSONField(required=False) state_on_success = serializers.CharField(required=False) From f7644b9a58094fba6b2c4278d6b734645a3064c2 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Mon, 10 Feb 2020 15:07:00 +0300 Subject: [PATCH 65/85] ADCM-1111 added confirmation to accept the license when updating the cluster --- web/src/app/core/services/detail.service.ts | 1 + .../shared/add-component/cluster.component.ts | 2 +- .../app/shared/components/upgrade.component.ts | 16 +++++++++++----- .../configuration/scheme/scheme.component.ts | 12 +++++------- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/web/src/app/core/services/detail.service.ts b/web/src/app/core/services/detail.service.ts index 8f89c261c2..f97fb5391f 100644 --- a/web/src/app/core/services/detail.service.ts +++ b/web/src/app/core/services/detail.service.ts @@ -142,6 +142,7 @@ export class ClusterService { } reset(): Observable { + if (!this.Current) return null; const typeName = this.Current.typeName; return this.api.get(this.Current.url).pipe( map(a => { diff --git a/web/src/app/shared/add-component/cluster.component.ts b/web/src/app/shared/add-component/cluster.component.ts index 84462a257e..c45d3194a8 100644 --- a/web/src/app/shared/add-component/cluster.component.ts +++ b/web/src/app/shared/add-component/cluster.component.ts @@ -11,7 +11,7 @@ // limitations under the License. import { Component, OnInit } from '@angular/core'; import { clearEmptyField, Cluster } from '@app/core/types'; -import { filter, tap } from 'rxjs/operators'; +import { filter } from 'rxjs/operators'; import { BaseFormDirective } from './base-form.directive'; import { GenName } from './naming'; diff --git a/web/src/app/shared/components/upgrade.component.ts b/web/src/app/shared/components/upgrade.component.ts index e86d6cb276..933f931ebf 100644 --- a/web/src/app/shared/components/upgrade.component.ts +++ b/web/src/app/shared/components/upgrade.component.ts @@ -13,8 +13,8 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { ApiService } from '@app/core/api'; import { EmmitRow } from '@app/core/types'; -import { Observable } from 'rxjs'; -import { filter } from 'rxjs/operators'; +import { Observable, of, concat } from 'rxjs'; +import { filter, switchMap, switchAll, concatAll } from 'rxjs/operators'; import { DialogComponent } from './dialog.component'; @@ -31,6 +31,7 @@ interface Upgrade { do: string; upgradable: boolean; from_edition: string[]; + license: 'unaccepted' | 'absent'; } @Component({ @@ -78,18 +79,23 @@ export class UpgradeComponent { constructor(private api: ApiService, private dialog: MatDialog) {} runUpgrade(item: Upgrade) { + const license$ = item.license === 'unaccepted' ? this.api.put(`bundle.license_url`, {}) : of(); + const do$ = this.api.post<{ id: number }>(item.do, {}); this.dialog .open(DialogComponent, { data: { title: 'Are you sure you want to upgrade?', text: item.description, disabled: !item.upgradable, - controls: ['Yes', 'No'] + controls: item.license === 'unaccepted' ? { label: 'Do you accept the license agreement?', buttons: ['Yes', 'No'] } : ['Yes', 'No'] } }) .beforeClosed() - .pipe(filter(yes => yes)) - .subscribe(() => this.api.post(item.do, {}).subscribe((result: { id: number }) => this.refresh.emit({ cmd: 'refresh', row: result }))); + .pipe( + filter(yes => yes), + switchMap(() => concat(license$, do$)) + ) + .subscribe(row => this.refresh.emit({ cmd: 'refresh', row })); } checkIssue(issue: any): boolean { diff --git a/web/src/app/shared/configuration/scheme/scheme.component.ts b/web/src/app/shared/configuration/scheme/scheme.component.ts index 6f16092e6e..d714115ff5 100644 --- a/web/src/app/shared/configuration/scheme/scheme.component.ts +++ b/web/src/app/shared/configuration/scheme/scheme.component.ts @@ -50,16 +50,14 @@ export class SchemeComponent implements OnInit { if (this.currentType === 'list') { this.items = (this.options.value as Array).map(a => { - return { value: a, rules: this.rules }; + return { value: a, rules: this.rules }; }); } else if (this.currentType === 'dict') { - - this.items = Object.keys(this.value).map(b => { - const c = this.findRule(b); - return {value: this.value[b], rules: c}; - }); + this.items = Object.keys(this.value).map(b => { + const c = this.findRule(b); + return { value: this.value[b], rules: c }; + }); } else { - } } From e938c896e78d9524e9f790ac6a0dca34f66befcd Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Mon, 10 Feb 2020 15:11:00 +0300 Subject: [PATCH 66/85] ADCM-1111 unsubscribe --- web/src/app/shared/components/upgrade.component.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/web/src/app/shared/components/upgrade.component.ts b/web/src/app/shared/components/upgrade.component.ts index 933f931ebf..fb0f565ed4 100644 --- a/web/src/app/shared/components/upgrade.component.ts +++ b/web/src/app/shared/components/upgrade.component.ts @@ -17,6 +17,7 @@ import { Observable, of, concat } from 'rxjs'; import { filter, switchMap, switchAll, concatAll } from 'rxjs/operators'; import { DialogComponent } from './dialog.component'; +import { BaseDirective } from '../directives'; interface UpgradeRow { upgradable: boolean; @@ -32,6 +33,7 @@ interface Upgrade { upgradable: boolean; from_edition: string[]; license: 'unaccepted' | 'absent'; + license_url: string; } @Component({ @@ -61,7 +63,7 @@ interface Upgrade { ` }) -export class UpgradeComponent { +export class UpgradeComponent extends BaseDirective { list$: Observable; row: UpgradeRow; @@ -76,10 +78,12 @@ export class UpgradeComponent { @Output() refresh: EventEmitter = new EventEmitter(); - constructor(private api: ApiService, private dialog: MatDialog) {} + constructor(private api: ApiService, private dialog: MatDialog) { + super(); + } runUpgrade(item: Upgrade) { - const license$ = item.license === 'unaccepted' ? this.api.put(`bundle.license_url`, {}) : of(); + const license$ = item.license === 'unaccepted' ? this.api.put(`${item.license_url}accept/`, {}) : of(); const do$ = this.api.post<{ id: number }>(item.do, {}); this.dialog .open(DialogComponent, { @@ -92,6 +96,7 @@ export class UpgradeComponent { }) .beforeClosed() .pipe( + this.takeUntil(), filter(yes => yes), switchMap(() => concat(license$, do$)) ) From 8b00fc6981410cba8c48cd52693336934bbe19dd Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Mon, 10 Feb 2020 20:40:51 +0300 Subject: [PATCH 67/85] ADCM-786 sorting of list by columns --- .../components/list/base-list.directive.ts | 5 +- .../components/list/list.component.html | 2 +- .../shared/components/list/list.component.ts | 44 +++------- .../components/list/multi-sort.directive.ts | 83 +++++++++++++++++++ web/src/app/shared/directives/index.ts | 1 - .../shared/directives/multi-sort.directive.ts | 52 ------------ web/src/app/shared/shared.module.ts | 11 +-- 7 files changed, 99 insertions(+), 99 deletions(-) create mode 100644 web/src/app/shared/components/list/multi-sort.directive.ts delete mode 100644 web/src/app/shared/directives/multi-sort.directive.ts diff --git a/web/src/app/shared/components/list/base-list.directive.ts b/web/src/app/shared/components/list/base-list.directive.ts index f4367fd271..bb13679a94 100644 --- a/web/src/app/shared/components/list/base-list.directive.ts +++ b/web/src/app/shared/components/list/base-list.directive.ts @@ -46,8 +46,8 @@ export class BaseListDirective extends SocketListener implements OnInit, OnDestr this.parent.route.paramMap .pipe( - filter(p => this.checkParam(p)), - this.takeUntil() + this.takeUntil(), + filter(p => this.checkParam(p)) ) .subscribe(p => { if (+p.get('page') === 0) { @@ -85,7 +85,6 @@ export class BaseListDirective extends SocketListener implements OnInit, OnDestr } socketListener(m: EventMessage): void { - /** check upgradable */ if (m.event === 'create' && m.object.type === 'bundle' && this.typeName === 'cluster') { this.refresh(m.object.id); diff --git a/web/src/app/shared/components/list/list.component.html b/web/src/app/shared/components/list/list.component.html index 42368ece49..0f76fdf5da 100644 --- a/web/src/app/shared/components/list/list.component.html +++ b/web/src/app/shared/components/list/list.component.html @@ -4,7 +4,7 @@ --> - + diff --git a/web/src/app/shared/components/list/list.component.ts b/web/src/app/shared/components/list/list.component.ts index 78b6bb7a4e..57ff422fb5 100644 --- a/web/src/app/shared/components/list/list.component.ts +++ b/web/src/app/shared/components/list/list.component.ts @@ -10,18 +10,7 @@ // See the License for the specific language governing permissions and // limitations under the License. import { SelectionModel } from '@angular/cdk/collections'; -import { - AfterViewInit, - Component, - ElementRef, - EventEmitter, - Input, - OnInit, - Output, - QueryList, - ViewChild, - ViewChildren, -} from '@angular/core'; +import { Component, ElementRef, EventEmitter, Input, OnInit, Output, QueryList, ViewChild, ViewChildren } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; import { MatPaginator, PageEvent } from '@angular/material/paginator'; import { MatSort, MatSortHeader, Sort } from '@angular/material/sort'; @@ -35,7 +24,7 @@ import { DialogComponent } from '../dialog.component'; enum Direction { '' = '', 'asc' = '', - 'desc' = '-', + 'desc' = '-' } export interface ListResult { @@ -48,9 +37,9 @@ export interface ListResult { @Component({ selector: 'app-list', templateUrl: './list.component.html', - styleUrls: ['./list.component.scss'], + styleUrls: ['./list.component.scss'] }) -export class ListComponent implements OnInit, AfterViewInit { +export class ListComponent implements OnInit { selection = new SelectionModel(true, []); current: any = {}; type: TypeName; @@ -90,21 +79,9 @@ export class ListComponent implements OnInit, AfterViewInit { constructor(public dialog: MatDialog, public router: Router, public route: ActivatedRoute) {} - ngAfterViewInit(): void { - this.matSortHeader.map(a => { - a.nativeElement.addEventListener('mousedown', (e: MouseEvent) => (this.addToSorting = e.shiftKey)); - a.nativeElement.addEventListener('mouseleave', (e: MouseEvent) => { - // ??? may be ChangeDetectorRef.detectChanges() - const sp = this.sortParam; - setTimeout(() => (this.sortParam = ''), 100); - setTimeout(() => (this.sortParam = sp), 200); - }); - }); - } - getSortParam(a: Sort) { const penis: { [key: string]: string[] } = { - prototype_version: ['prototype_display_name', 'prototype_version'], + prototype_version: ['prototype_display_name', 'prototype_version'] }; const dumb = penis[a.active] ? penis[a.active] : [a.active], @@ -135,8 +112,8 @@ export class ListComponent implements OnInit, AfterViewInit { page: pageIndex, limit: pageSize, filter: _filter, - ordering, - }, + ordering + } ], { relativeTo: this.route } ); @@ -151,7 +128,7 @@ export class ListComponent implements OnInit, AfterViewInit { const f = this.route.snapshot.paramMap.get('filter') || ''; const ordering = this.getSortParam(this.sort); this.router.navigate(['./', { page: pageEvent.pageIndex, limit: pageEvent.pageSize, filter: f, ordering }], { - relativeTo: this.route, + relativeTo: this.route }); } @@ -213,12 +190,11 @@ export class ListComponent implements OnInit, AfterViewInit { data: { title: `Deleting "${row.name || row.fqdn}"`, text: 'Are you sure?', - controls: ['Yes', 'No'], - }, + controls: ['Yes', 'No'] + } }) .beforeClosed() .pipe(filter(yes => yes)) .subscribe(() => this.listItemEvt.emit({ cmd: 'delete', row })); } - } diff --git a/web/src/app/shared/components/list/multi-sort.directive.ts b/web/src/app/shared/components/list/multi-sort.directive.ts new file mode 100644 index 0000000000..a96a373da1 --- /dev/null +++ b/web/src/app/shared/components/list/multi-sort.directive.ts @@ -0,0 +1,83 @@ +// 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. +import { Directive, ElementRef, Input, Renderer2, HostListener, Output, EventEmitter } from '@angular/core'; + +@Directive({ + selector: '[appMultiSort]' +}) +export class MultiSortDirective { + shiftKey = false; + _params: string[] = []; + + @Input('appMultiSort') set sortParam(param: string) { + const el = this.el.nativeElement; + this._params = param.split(','); + this.hideAllArrows(el); + setTimeout(() => this._params.map(p => this.preCell(p, el)), 0); + } + + @Output() mousedownevent = new EventEmitter(); + + @HostListener('mousedown', ['$event']) onmousedown(e: MouseEvent) { + this.shiftKey = e.shiftKey; + this.mousedownevent.emit(e.shiftKey); + } + + @HostListener('mouseover', ['$event.target']) onmouseover(h: HTMLElement) { + const el = this.el.nativeElement; + this._params.map(p => this.preCell(p, el)); + } + + @HostListener('mouseout', ['$event.target']) mouseleave(row: HTMLElement) { + const el = this.el.nativeElement; + setTimeout(() => this._params.map(p => this.preCell(p, el)), 300); + } + + constructor(private el: ElementRef, private renderer: Renderer2) {} + + hideAllArrows(el) { + Array.from(el.getElementsByTagName('mat-header-cell')).forEach(e => { + const a = e.querySelector('div.mat-sort-header-container>div.mat-sort-header-arrow'); + if (a) this.renderer.setStyle(a, 'opacity', 0); + }); + } + + preCell(p: string, el: HTMLElement) { + const direction = p[0] === '-' ? 'descending' : 'ascending', + active = p[0] === '-' ? p.substr(1) : p; + + const column = el.querySelector(`mat-header-cell.mat-column-${active}`) || el.querySelector(`mat-header-cell[mat-sort-header="${active}"]`); + if (p) { + this.renderer.setAttribute(column, 'aria-sort', direction); + + const container = column.querySelector('div.mat-sort-header-container'); + this.renderer.addClass(container, 'mat-sort-header-sorted'); + + const arrow = container.querySelector('div.mat-sort-header-arrow'); + if (arrow) { + this.renderer.setStyle(arrow, 'opacity', 1); + this.renderer.setStyle(arrow, 'transform', 'translateY(0px)'); + + const indicator = arrow.querySelector('div.mat-sort-header-indicator'); + this.renderer.setStyle(indicator, 'transform', direction === 'descending' ? 'translateY(10px)' : 'translateY(0px)'); + + if (direction === 'descending') { + const left = indicator.querySelector('.mat-sort-header-pointer-left'); + this.renderer.setStyle(left, 'transform', 'rotate(45deg)'); + + const right = indicator.querySelector('.mat-sort-header-pointer-right'); + this.renderer.setStyle(right, 'transform', 'rotate(-45deg)'); + } + } + } + } +} diff --git a/web/src/app/shared/directives/index.ts b/web/src/app/shared/directives/index.ts index 029e0bb35c..1b2f58609e 100644 --- a/web/src/app/shared/directives/index.ts +++ b/web/src/app/shared/directives/index.ts @@ -16,4 +16,3 @@ export * from './m-textarea.directive'; export * from './base.directive'; export * from './scroll.directive'; export * from './infinity-scroll.directive'; -export * from './multi-sort.directive'; diff --git a/web/src/app/shared/directives/multi-sort.directive.ts b/web/src/app/shared/directives/multi-sort.directive.ts deleted file mode 100644 index da0f5d6b45..0000000000 --- a/web/src/app/shared/directives/multi-sort.directive.ts +++ /dev/null @@ -1,52 +0,0 @@ -// 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. -import { Directive, ElementRef, Input, Renderer2 } from '@angular/core'; - -@Directive({ - selector: '[appMultiSort]', -}) -export class MultiSortDirective { - @Input('appMultiSort') set sortParam(param: string) { - const el = this.el.nativeElement; - Array.from(el.getElementsByTagName('mat-header-cell')).forEach(e => { - const a = e.querySelector('div.mat-sort-header-container>div.mat-sort-header-arrow'); - if (a) this.renderer.setStyle(a, 'opacity', 0); - }); - setTimeout(() => { - param.split(',').forEach(cell => { - const direction = cell[0] === '-' ? 'descending' : 'ascending', - active = cell[0] === '-' ? cell.substr(1) : cell; - const c = el.querySelector(`mat-header-cell.mat-column-${active}`) || el.querySelector(`mat-header-cell[mat-sort-header="${active}"]`); - if (c) { - this.renderer.setAttribute(c, 'aria-sort', direction); - const cont = c.querySelector('div.mat-sort-header-container'); - this.renderer.addClass(cont, 'mat-sort-header-sorted'); - const arrow = cont.querySelector('div.mat-sort-header-arrow'); - - this.renderer.setStyle(arrow, 'opacity', 1); - this.renderer.setStyle(arrow, 'transform', 'translateY(0px)'); - - const ind = arrow.querySelector('div.mat-sort-header-indicator'); - this.renderer.setStyle(ind, 'transform', direction === 'descending' ? 'translateY(10px)' : 'translateY(0px)'); - if (direction === 'descending') { - const left = ind.querySelector('.mat-sort-header-pointer-left'); - this.renderer.setStyle(left, 'transform', 'rotate(45deg)'); - const right = ind.querySelector('.mat-sort-header-pointer-right'); - this.renderer.setStyle(right, 'transform', 'rotate(-45deg)'); - } - } - }); - }, 100); - } - - constructor(private el: ElementRef, private renderer: Renderer2) {} -} diff --git a/web/src/app/shared/shared.module.ts b/web/src/app/shared/shared.module.ts index a5c735dfb8..84c00d1b64 100644 --- a/web/src/app/shared/shared.module.ts +++ b/web/src/app/shared/shared.module.ts @@ -30,21 +30,16 @@ import { UpgradeComponent, } from './components'; import { ActionsDirective } from './components/actions/actions.directive'; +import { MultiSortDirective } from './components/list/multi-sort.directive'; import { SimpleTextComponent } from './components/tooltip'; import { ConfigurationModule } from './configuration/configuration.module'; -import { - DynamicDirective, - HoverDirective, - InfinityScrollDirective, - MultiSortDirective, -} from './directives'; +import { DetailsModule } from './details/details.module'; +import { DynamicDirective, HoverDirective, InfinityScrollDirective } from './directives'; import { FormElementsModule } from './form-elements/form-elements.module'; import { HostComponentsMapModule } from './host-components-map/host-components-map.module'; import { MaterialModule } from './material.module'; import { BreakRowPipe, TagEscPipe } from './pipes'; import { StuffModule } from './stuff.module'; -import { DetailsModule } from './details/details.module'; - @NgModule({ imports: [ From 7c5e7a7d44383dba8a53ea45eaba059b7bb258d0 Mon Sep 17 00:00:00 2001 From: Alexandr Alferov Date: Tue, 11 Feb 2020 11:43:32 +0300 Subject: [PATCH 68/85] ADCM-1126 Added fail_msg and success_msg for adcm_check. --- python/ansible/plugins/action/adcm_check.py | 28 +++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/python/ansible/plugins/action/adcm_check.py b/python/ansible/plugins/action/adcm_check.py index 92cae038e1..647caa86f7 100644 --- a/python/ansible/plugins/action/adcm_check.py +++ b/python/ansible/plugins/action/adcm_check.py @@ -68,7 +68,7 @@ class ActionModule(ActionBase): TRANSFERS_FILES = False - _VALID_ARGS = frozenset(('title', 'result', 'msg')) + _VALID_ARGS = frozenset(('title', 'result', 'msg', 'fail_msg', 'success_msg')) def run(self, tmp=None, task_vars=None): job_id = None @@ -77,16 +77,30 @@ def run(self, tmp=None, task_vars=None): result = super(ActionModule, self).run(tmp, task_vars) - if ('title' not in self._task.args or - 'result' not in self._task.args or - 'msg' not in self._task.args): - return {"failed": True, "msg": "title, result and msg are mandatory args of adcm_check"} + old_optional_condition = 'msg' in self._task.args + new_optional_condition = 'fail_msg' in self._task.args and 'success_msg' in self._task.args + optional_condition = old_optional_condition or new_optional_condition + required_condition = ( + 'title' in self._task.args and + 'result' in self._task.args and + optional_condition + ) + if required_condition: + return { + "failed": True, + "msg": ("title, result and msg, fail_msg or success" + "_msg are mandatory args of adcm_check") + } + result = super(ActionModule, self).run(tmp, task_vars) title = self._task.args['title'] result = self._task.args['result'] - msg = self._task.args['msg'] + msg = self._task.get('msg', '') + fail_msg = self._task.args.get('fail_msg', '') + success_msg = self._task.args.get('success_msg', '') - log.debug('ansible adcm_check: %s, %s, %s, %s', job_id, title, result, msg) + log.debug('ansible adcm_check: %s, %s, %s, %s, %s, %s', + job_id, title, result, msg, fail_msg, success_msg) try: cm.job.log_check(job_id, title, result, msg) From 39af995966f74af140e83a46cdadd2d0500cda96 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Tue, 11 Feb 2020 11:55:14 +0300 Subject: [PATCH 69/85] ADCM-1111 has added a license text --- .../shared/components/upgrade.component.ts | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/web/src/app/shared/components/upgrade.component.ts b/web/src/app/shared/components/upgrade.component.ts index fb0f565ed4..fff2f1c077 100644 --- a/web/src/app/shared/components/upgrade.component.ts +++ b/web/src/app/shared/components/upgrade.component.ts @@ -14,7 +14,7 @@ import { MatDialog } from '@angular/material/dialog'; import { ApiService } from '@app/core/api'; import { EmmitRow } from '@app/core/types'; import { Observable, of, concat } from 'rxjs'; -import { filter, switchMap, switchAll, concatAll } from 'rxjs/operators'; +import { filter, switchMap, switchAll, concatAll, map } from 'rxjs/operators'; import { DialogComponent } from './dialog.component'; import { BaseDirective } from '../directives'; @@ -85,24 +85,34 @@ export class UpgradeComponent extends BaseDirective { runUpgrade(item: Upgrade) { const license$ = item.license === 'unaccepted' ? this.api.put(`${item.license_url}accept/`, {}) : of(); const do$ = this.api.post<{ id: number }>(item.do, {}); - this.dialog - .open(DialogComponent, { - data: { - title: 'Are you sure you want to upgrade?', - text: item.description, - disabled: !item.upgradable, - controls: item.license === 'unaccepted' ? { label: 'Do you accept the license agreement?', buttons: ['Yes', 'No'] } : ['Yes', 'No'] - } - }) - .beforeClosed() + this.fork(item) .pipe( - this.takeUntil(), - filter(yes => yes), - switchMap(() => concat(license$, do$)) + switchMap(text => + this.dialog + .open(DialogComponent, { + data: { + title: 'Are you sure you want to upgrade?', + text, + disabled: !item.upgradable, + controls: item.license === 'unaccepted' ? { label: 'Do you accept the license agreement?', buttons: ['Yes', 'No'] } : ['Yes', 'No'] + } + }) + .beforeClosed() + .pipe( + this.takeUntil(), + filter(yes => yes), + switchMap(() => concat(license$, do$)) + ) + ) ) .subscribe(row => this.refresh.emit({ cmd: 'refresh', row })); } + fork(item: Upgrade) { + const flag = item.license === 'unaccepted'; + return flag ? this.api.get<{ text: string }>(item.license_url).pipe(map(a => a.text)) : of(item.description); + } + checkIssue(issue: any): boolean { return issue && !!Object.keys(issue).length; } From 5341f3234ae21aed953f86bb387d218c9e69fdda Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Tue, 11 Feb 2020 12:40:45 +0300 Subject: [PATCH 70/85] ADCM-1122 saves and checks the version without reload --- web/src/app/core/services/config.service.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/web/src/app/core/services/config.service.ts b/web/src/app/core/services/config.service.ts index 2dbcd111ed..9a94ac7a0f 100644 --- a/web/src/app/core/services/config.service.ts +++ b/web/src/app/core/services/config.service.ts @@ -14,7 +14,6 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; - const CONFIG_URL = '/assets/config.json'; export interface IConfig { version: string; @@ -42,10 +41,13 @@ export class ConfigService { } checkVersion(c: IConfig): IConfig | null { - if (this.version !== c.version) { - this.version = c.version; + const version = `${c.version}-${c.commit_id}`; + if (this.version && this.version !== version) { + this.version = version; return null; - } else return c; + } + this.version = version; + return c; } load() { From abe23a3cefe995e5d5a14e085e5d51191286abdf Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Tue, 11 Feb 2020 13:40:27 +0300 Subject: [PATCH 71/85] fixed mistake of load object after socket events --- web/src/app/core/services/detail.service.ts | 4 ++-- web/src/app/shared/details/detail.component.ts | 15 +++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/web/src/app/core/services/detail.service.ts b/web/src/app/core/services/detail.service.ts index f97fb5391f..e7c2adc5a9 100644 --- a/web/src/app/core/services/detail.service.ts +++ b/web/src/app/core/services/detail.service.ts @@ -9,7 +9,7 @@ // 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. -import { Injectable } from '@angular/core'; +import { Injectable, ɵEMPTY_MAP } from '@angular/core'; import { ParamMap } from '@angular/router'; import { ApiService } from '@app/core/api'; import { IAction, Bundle, Cluster, Entities, Host, IImport, Job, Log, Provider, Service, TypeName } from '@app/core/types'; @@ -142,7 +142,7 @@ export class ClusterService { } reset(): Observable { - if (!this.Current) return null; + if (!this.Current) return EMPTY; const typeName = this.Current.typeName; return this.api.get(this.Current.url).pipe( map(a => { diff --git a/web/src/app/shared/details/detail.component.ts b/web/src/app/shared/details/detail.component.ts index 2e550a2a9b..51d0ecff3a 100644 --- a/web/src/app/shared/details/detail.component.ts +++ b/web/src/app/shared/details/detail.component.ts @@ -16,7 +16,7 @@ import { EventMessage, SocketState } from '@app/core/store'; import { Cluster, Entities, Host, IAction, Issue } from '@app/core/types'; import { Store } from '@ngrx/store'; import { Observable, of } from 'rxjs'; -import { switchMap, tap } from 'rxjs/operators'; +import { switchMap, tap, filter } from 'rxjs/operators'; import { SocketListener } from '../directives/base.directive'; import { CrumbsItem, NavigationService } from './navigation.service'; @@ -69,19 +69,17 @@ export class DetailComponent extends SocketListener implements OnInit, OnDestroy } socketListener(m: EventMessage) { - - if (m.event === 'create' && m.object.type === 'bundle') { - this.model$ = this.current.reset(); + this.updateAll(m); } if (this.current.Current && this.current.Current.typeName === m.object.type && this.current.Current.id === m.object.id) { if (m.event === 'change_job_status' && this.current.Current.typeName === 'job') { - this.current.reset().subscribe(a => this.initValue(a.current, m)); + this.updateAll(m); } if (m.event === 'change_state' || m.event === 'upgrade' || m.event === 'raise_issue') { - this.current.reset().subscribe(a => this.initValue(a.current, m)); + this.updateAll(m); } if (m.event === 'clear_issue') { @@ -95,6 +93,7 @@ export class DetailComponent extends SocketListener implements OnInit, OnDestroy this.updateView(); } } + if ( this.current.Cluster && m.event === 'clear_issue' && @@ -107,6 +106,10 @@ export class DetailComponent extends SocketListener implements OnInit, OnDestroy } } + updateAll(m?: EventMessage) { + this.current.reset().pipe(filter(a => !!a)).subscribe(a => this.initValue(a.current, m)); + } + initValue(a: Entities, m?: EventMessage) { this.actions$ = !a.actions || !a.actions.length ? this.current.getActions() : of(a.actions); this.updateView(); From 90ea065b1f36c4d284a7a9a54b89c33f85b3956c Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Tue, 11 Feb 2020 14:08:08 +0300 Subject: [PATCH 72/85] ADCM-1136 had excluded read_only field and empty object from the configs save --- .../app/shared/configuration/field.service.ts | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/web/src/app/shared/configuration/field.service.ts b/web/src/app/shared/configuration/field.service.ts index 7161c7ad2b..a1d6c354d5 100644 --- a/web/src/app/shared/configuration/field.service.ts +++ b/web/src/app/shared/configuration/field.service.ts @@ -13,16 +13,7 @@ import { Injectable } from '@angular/core'; import { AbstractControl, FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms'; import { getControlType, getPattern, isObject } from '@app/core/types'; -import { - ConfigOptions, - ConfigResultTypes, - ConfigValueTypes, - FieldOptions, - FieldStack, - IConfig, - IStructure, - PanelOptions, -} from './types'; +import { ConfigOptions, ConfigResultTypes, ConfigValueTypes, FieldOptions, FieldStack, IConfig, IStructure, PanelOptions } from './types'; import { YspecService, matchType } from './yspec/yspec.service'; export interface IToolsEvent { @@ -136,7 +127,7 @@ export class FieldService { } toFormGroup(options: (FieldOptions | PanelOptions)[]): FormGroup { - this.form = this.fb.group(options.reduce((p, c) => this.runByTree(c, p), {})); + this.form = this.fb.group(options.reduce((p, c) => this.runByTree(c, p), {})); return this.form; } @@ -220,10 +211,13 @@ export class FieldService { return Object.keys(value).reduce((p, c) => { const data = value[c]; const field = this.findField(c, parentName); - if (field) { + + if (field && !field.read_only) { if (field.type === 'structure') p[c] = this.runYspecParse(data, field); - else if (isObject(data) && !excluteTypes.includes(field.type)) p[c] = this.runParse(data, field.name); - else if (field) p[c] = this.checkValue(data, field.type); + else if (isObject(data) && !excluteTypes.includes(field.type)) { + const br = this.runParse(data, field.name); + if (Object.keys(br).length) p[c] = br; + } else if (field) p[c] = this.checkValue(data, field.type); } return p; }, {}); From 943142dc36b30a31c742c63b09d9f4b0b4403d7a Mon Sep 17 00:00:00 2001 From: Alexandr Alferov Date: Tue, 11 Feb 2020 22:00:26 +0300 Subject: [PATCH 73/85] ADCM-1126 Processing success_msg and fail_msg for log check. --- python/ansible/plugins/action/adcm_check.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/python/ansible/plugins/action/adcm_check.py b/python/ansible/plugins/action/adcm_check.py index 647caa86f7..71106497dd 100644 --- a/python/ansible/plugins/action/adcm_check.py +++ b/python/ansible/plugins/action/adcm_check.py @@ -11,9 +11,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -# pylint: disable=wrong-import-position,unused-import +# pylint: disable=wrong-import-position, unused-import, import-error from __future__ import absolute_import, division, print_function + __metaclass__ = type ANSIBLE_METADATA = {'metadata_version': '1.1', 'supported_by': 'Arenadata'} @@ -66,7 +67,6 @@ class ActionModule(ActionBase): - TRANSFERS_FILES = False _VALID_ARGS = frozenset(('title', 'result', 'msg', 'fail_msg', 'success_msg')) @@ -81,11 +81,10 @@ def run(self, tmp=None, task_vars=None): new_optional_condition = 'fail_msg' in self._task.args and 'success_msg' in self._task.args optional_condition = old_optional_condition or new_optional_condition required_condition = ( - 'title' in self._task.args and - 'result' in self._task.args and - optional_condition + 'title' in self._task.args and 'result' in self._task.args and optional_condition ) - if required_condition: + + if not required_condition: return { "failed": True, "msg": ("title, result and msg, fail_msg or success" @@ -95,7 +94,7 @@ def run(self, tmp=None, task_vars=None): result = super(ActionModule, self).run(tmp, task_vars) title = self._task.args['title'] result = self._task.args['result'] - msg = self._task.get('msg', '') + msg = self._task.args.get('msg', '') fail_msg = self._task.args.get('fail_msg', '') success_msg = self._task.args.get('success_msg', '') @@ -103,6 +102,10 @@ def run(self, tmp=None, task_vars=None): job_id, title, result, msg, fail_msg, success_msg) try: + if result: + msg = success_msg if success_msg else msg + else: + msg = fail_msg if fail_msg else msg cm.job.log_check(job_id, title, result, msg) except AdcmEx as e: return {"failed": True, "msg": e.code + ":" + e.msg} From e685941b57ea6e66ef1b666ea3d196e5dbd815a0 Mon Sep 17 00:00:00 2001 From: Alexandr Alferov Date: Wed, 12 Feb 2020 13:58:29 +0300 Subject: [PATCH 74/85] ADCM-1126 Duplicate row deleted. --- python/ansible/plugins/action/adcm_check.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/python/ansible/plugins/action/adcm_check.py b/python/ansible/plugins/action/adcm_check.py index 71106497dd..a0b30b2365 100644 --- a/python/ansible/plugins/action/adcm_check.py +++ b/python/ansible/plugins/action/adcm_check.py @@ -75,8 +75,6 @@ def run(self, tmp=None, task_vars=None): if task_vars is not None and 'job' in task_vars or 'id' in task_vars['job']: job_id = task_vars['job']['id'] - result = super(ActionModule, self).run(tmp, task_vars) - old_optional_condition = 'msg' in self._task.args new_optional_condition = 'fail_msg' in self._task.args and 'success_msg' in self._task.args optional_condition = old_optional_condition or new_optional_condition From b24b293008f8491879049aed51196fd69e47a951 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Fri, 14 Feb 2020 13:19:17 +0300 Subject: [PATCH 75/85] ADCM-1134 Long hostnames --- .../add-component/host2cluster.component.ts | 4 +-- .../app/shared/components/dialog.component.ts | 2 +- .../components/list/list.component.html | 8 +++--- .../components/list/list.component.scss | 28 ++++++++++++------- web/src/styles.scss | 4 +++ 5 files changed, 29 insertions(+), 17 deletions(-) diff --git a/web/src/app/shared/add-component/host2cluster.component.ts b/web/src/app/shared/add-component/host2cluster.component.ts index 5cee883874..44b6347ffd 100644 --- a/web/src/app/shared/add-component/host2cluster.component.ts +++ b/web/src/app/shared/add-component/host2cluster.component.ts @@ -28,7 +28,7 @@ import { HostComponent } from './host.component';
- + @@ -46,7 +46,7 @@ import { HostComponent } from './host.component'; `, styles: [ '.tools {position: relative; height: 40px;} .tools>button { position: absolute; right: 0;}', - '.full { display: flex;padding-left: 6px; margin: 3px 0; } .full>label { flex: 1 0 auto; vertical-align: middle; line-height: 40px; }', + '.full { display: flex;padding-left: 6px; margin: 3px 0; justify-content: space-between; } .full>label { vertical-align: middle; line-height: 40px; }', '.full:nth-child(odd) {background-color: #4e4e4e;}', '.full:hover {background-color: #5e5e5e; }' ] diff --git a/web/src/app/shared/components/dialog.component.ts b/web/src/app/shared/components/dialog.component.ts index c6bc33c863..f276cf6aab 100644 --- a/web/src/app/shared/components/dialog.component.ts +++ b/web/src/app/shared/components/dialog.component.ts @@ -28,7 +28,7 @@ export interface DialogData { @Component({ selector: 'app-dialog', template: ` -

{{ data.title || 'Notification' }}

+

{{ data.title || 'Notification' }}

{{ data.text }}
diff --git a/web/src/app/shared/components/list/list.component.html b/web/src/app/shared/components/list/list.component.html index 0f76fdf5da..d4df7b835f 100644 --- a/web/src/app/shared/components/list/list.component.html +++ b/web/src/app/shared/components/list/list.component.html @@ -119,8 +119,8 @@ - State - + State + autorenew {{ row.state }} @@ -217,8 +217,8 @@ - FQDN - + FQDN + {{ row.fqdn }} diff --git a/web/src/app/shared/components/list/list.component.scss b/web/src/app/shared/components/list/list.component.scss index 5858d9b919..ce87e4ba56 100644 --- a/web/src/app/shared/components/list/list.component.scss +++ b/web/src/app/shared/components/list/list.component.scss @@ -1,21 +1,29 @@ .m-left { - display: inline-block; - margin-left: 40px; + display: inline-block; + margin-left: 40px; } .col-odd { - padding: 0 10px; + padding: 0 10px; } .select-in-cell { - flex-basis: 80%; - max-width: 240px; + flex-basis: 80%; + max-width: 240px; } -mat-header-cell.control, mat-cell.control { - flex-basis: 60px; +mat-header-cell.control, +mat-cell.control { + flex-basis: 60px; } -.overflow { - overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-right: 10px; -} \ No newline at end of file +.width100 { + flex-grow: 0; + flex-basis: 100px; +} + +.width30pr { + flex-grow: 1; + flex-basis: 30%; + width: 100px +} diff --git a/web/src/styles.scss b/web/src/styles.scss index 5e2ee4387a..7c1045f655 100644 --- a/web/src/styles.scss +++ b/web/src/styles.scss @@ -119,6 +119,10 @@ body { } } +.overflow { + overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-right: 10px; +} + mat-checkbox.advanced>label>span { border-bottom: dotted 1px #00e676; line-height: 20px!important; From a54d1b3569f0c24ba2e711d996cfe828820d3eec Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Fri, 14 Feb 2020 13:33:54 +0300 Subject: [PATCH 76/85] ADCM-1138 resizing has fixed --- .../host-components-map/much-2-many/much-2-many.component.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/src/app/shared/host-components-map/much-2-many/much-2-many.component.ts b/web/src/app/shared/host-components-map/much-2-many/much-2-many.component.ts index 1c48643753..42ee73788e 100644 --- a/web/src/app/shared/host-components-map/much-2-many/much-2-many.component.ts +++ b/web/src/app/shared/host-components-map/much-2-many/much-2-many.component.ts @@ -34,9 +34,10 @@ export class Much2ManyComponent { isError() { const form = this.service.formGroup; - if ('service_id' in this.model) { + if ('service_id' in this.model && Object.keys(form.controls).length) { const sc = this.model as CompTile; const control = form.controls[`${sc.service_id}/${sc.id}`]; + if (!control) return false; return control.invalid; } else return false; } From 703d03eaa64c3580d9215bd5c7f058847daa6da8 Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Tue, 18 Feb 2020 17:09:29 +0300 Subject: [PATCH 77/85] ADCM-1146 fixed config for actions --- web/src/app/core/services/detail.service.ts | 2 +- .../actions/master/master.component.ts | 7 +- .../app/shared/configuration/field.service.ts | 99 ++++++++++--------- .../configuration/fields/fields.component.ts | 4 +- .../group-fields/group-fields.component.html | 2 +- .../group-fields/group-fields.component.ts | 13 ++- .../configuration/main/main.component.ts | 31 +++--- .../shared/form-elements/field.directive.ts | 2 +- 8 files changed, 91 insertions(+), 69 deletions(-) diff --git a/web/src/app/core/services/detail.service.ts b/web/src/app/core/services/detail.service.ts index e7c2adc5a9..3896e37ad5 100644 --- a/web/src/app/core/services/detail.service.ts +++ b/web/src/app/core/services/detail.service.ts @@ -142,7 +142,7 @@ export class ClusterService { } reset(): Observable { - if (!this.Current) return EMPTY; + if (!this.Current || !this.worker) return EMPTY; const typeName = this.Current.typeName; return this.api.get(this.Current.url).pipe( map(a => { diff --git a/web/src/app/shared/components/actions/master/master.component.ts b/web/src/app/shared/components/actions/master/master.component.ts index 21308316af..460f502073 100644 --- a/web/src/app/shared/components/actions/master/master.component.ts +++ b/web/src/app/shared/components/actions/master/master.component.ts @@ -17,6 +17,7 @@ import { DynamicComponent, DynamicEvent, ServiceHostComponent } from '@app/share import { BaseDirective } from '../../../directives/base.directive'; import { ConfigFieldsComponent } from '@app/shared/configuration/fields/fields.component'; import { ActionParameters } from '../actions.directive'; +import { FieldService } from '@app/shared/configuration/field.service'; @Component({ selector: 'app-master', @@ -33,7 +34,7 @@ export class ActionMasterComponent extends BaseDirective implements DynamicCompo arh: { parent: HTMLElement; holder: HTMLElement }; - constructor(private api: ApiService) { + constructor(private api: ApiService, private config: FieldService) { super(); } @@ -51,14 +52,14 @@ export class ActionMasterComponent extends BaseDirective implements DynamicCompo run(config: ConfigFieldsComponent, hostmap: ServiceHostComponent) { const data: any = {}; - if (config) data.value = config.form.value; + if (config) data.value = config.form; if (hostmap) data.hostmap = hostmap.service.statePost.data; const request$ = !this.isConfig && !this.isHmcRequired ? this.api.post(this.action.run, {}) : this.api.post(this.action.run, { - config: parseValueConfig(this.action.config.config, data.value), + config: this.config.parseValue(data.value, this.action.config.config), hc: data.hostmap, }); diff --git a/web/src/app/shared/configuration/field.service.ts b/web/src/app/shared/configuration/field.service.ts index a1d6c354d5..4addbcdb6d 100644 --- a/web/src/app/shared/configuration/field.service.ts +++ b/web/src/app/shared/configuration/field.service.ts @@ -25,10 +25,7 @@ export type controlType = 'boolean' | 'textbox' | 'textarea' | 'json' | 'passwor @Injectable() export class FieldService { - globalConfig: IConfig; - dataOptions: (FieldOptions | PanelOptions)[]; - formOptions: FieldOptions[]; - form = new FormGroup({}); + // globalConfig: IConfig; constructor(private fb: FormBuilder, private spec: YspecService) {} @@ -38,36 +35,45 @@ export class FieldService { isHidden = (a: FieldStack) => a.ui_options && (a.ui_options.invisible || a.ui_options.advanced); getPanels(data: IConfig): (FieldOptions | PanelOptions)[] { - this.globalConfig = data; - this.dataOptions = []; - - if (data && data.config.length) { - this.formOptions = data.config.filter(a => a.type !== 'group').map((a: FieldStack) => this.getFieldBy(a)); - data.config.filter(a => a.name !== '__main_info').map(a => this.fillDataOptions(a)); + // this.globalConfig = data; + + if (data && data.config) { + const fo = data.config.filter(a => a.type !== 'group' && a.subname); //.map((a: FieldStack) => this.getFieldBy(a)); + //return data.config.filter(a => a.name !== '__main_info' && a.type === 'group').map(a => this.fillDataOptions(a, fo)); + // if (!a.subname) return this.checkYspec(this.getFieldBy(a)); + return data.config + .filter(a => a.name !== '__main_info') + .reduce((p, c) => { + if (c.subname) return p; + if (c.type !== 'group') return [...p, this.getFieldBy(c)]; + else return [...p, this.fillDataOptions(c, fo)]; + }, []); } - return this.dataOptions; + return []; } - fillDataOptions(a: FieldStack) { - if (a.type === 'group') { - this.dataOptions.push({ - ...a, - hidden: this.isHidden(a), - options: this.formOptions.filter(b => b.name === a.name).map(b => this.checkYspec(b)) - }); - } else if (!a.subname) this.dataOptions.push(this.checkYspec(this.getFieldBy(a))); + fillDataOptions(a: FieldStack, fo: FieldStack[]) { + return { + ...a, + hidden: this.isHidden(a), + options: fo + .filter(b => b.name === a.name) + .map(b => this.getFieldBy(b)) + .map(c => { + c.name = c.subname; + return c; + }) + }; } - checkYspec(a: FieldOptions): FieldOptions | PanelOptions { - a.name = a.subname || a.name; - if (a.limits && a.limits.yspec) { - this.spec.Root = a.limits.yspec; - (a as IStructure).rules = this.spec.build(); - // const yspec = new YspecStructure(a); - // return yspec.output; - } - return a; - } + //checkYspec(a: FieldStack): FieldOptions | PanelOptions { + // a.name = a.subname || a.name; + // if (a.limits && a.limits.yspec) { + // this.spec.Root = a.limits.yspec; + // (a as IStructure).rules = this.spec.build(); + // } + // return a; + //} getFieldBy(item: FieldStack): FieldOptions { const params: FieldOptions = { @@ -127,8 +133,7 @@ export class FieldService { } toFormGroup(options: (FieldOptions | PanelOptions)[]): FormGroup { - this.form = this.fb.group(options.reduce((p, c) => this.runByTree(c, p), {})); - return this.form; + return this.fb.group(options.reduce((p, c) => this.runByTree(c, p), {})); } runByTree(field: FieldOptions | PanelOptions, controls: { [key: string]: {} }): { [key: string]: {} } { @@ -157,9 +162,8 @@ export class FieldService { return controls; } - filterApply(c: { advanced: boolean; search: string }): (FieldOptions | PanelOptions)[] { - this.dataOptions.filter(a => this.isVisibleField(a)).map(a => this.handleTree(a, c)); - return [...this.dataOptions]; + filterApply(dataOptions: (FieldOptions | PanelOptions)[], c: { advanced: boolean; search: string }): (FieldOptions | PanelOptions)[] { + return dataOptions.filter(a => this.isVisibleField(a)).map(a => this.handleTree(a, c)); } handleTree(a: FieldOptions | PanelOptions, c: { advanced: boolean; search: string }) { @@ -200,22 +204,22 @@ export class FieldService { * Check the data * */ - parseValue(): { [key: string]: string | number | boolean | object | [] } { - const __main_info = this.findField('__main_info'); - const value = __main_info && __main_info.required ? { ...this.form.value, __main_info: __main_info.value } : { ...this.form.value }; - return this.runParse(value); + parseValue(form: FormGroup, raw: FieldStack[]): { [key: string]: string | number | boolean | object | [] } { + const __main_info = this.findField(raw, '__main_info'); + const value = __main_info && __main_info.required ? { ...form.value, __main_info: __main_info.value } : { ...form.value }; + return this.runParse(raw, value); } - runParse(value: { [key: string]: any }, parentName?: string): { [key: string]: ConfigResultTypes } { + runParse(raw: FieldStack[], value: { [key: string]: any }, parentName?: string): { [key: string]: ConfigResultTypes } { const excluteTypes = ['json', 'map', 'list']; return Object.keys(value).reduce((p, c) => { const data = value[c]; - const field = this.findField(c, parentName); + const field = this.findField(raw, c, parentName); if (field && !field.read_only) { if (field.type === 'structure') p[c] = this.runYspecParse(data, field); else if (isObject(data) && !excluteTypes.includes(field.type)) { - const br = this.runParse(data, field.name); + const br = this.runParse(raw, data, field.name); if (Object.keys(br).length) p[c] = br; } else if (field) p[c] = this.checkValue(data, field.type); } @@ -223,15 +227,16 @@ export class FieldService { }, {}); } - findField(name: string, parentName?: string): FieldStack { - return this.globalConfig.config.find(a => (parentName ? a.name === parentName && a.subname === name : a.name === name)); + findField(raw: FieldStack[], name: string, parentName?: string): FieldStack { + return raw.find(a => (parentName ? a.name === parentName && a.subname === name : a.name === name)); } runYspecParse(value: any, field: FieldStack) { - const name = field.subname || field.name; - const yo = this.dataOptions.find(a => a.name === field.name) as PanelOptions; - const po = yo.options.find(a => a.name === field.subname) as PanelOptions; - return this.runYspecByOptions(value, po); + console.warn('under development'); + // const name = field.subname || field.name; + // const yo = this.dataOptions.find(a => a.name === field.name) as PanelOptions; + // const po = yo.options.find(a => a.name === field.subname) as PanelOptions; + // return this.runYspecByOptions(value, po); } runYspecByOptions(value: any, op: PanelOptions) { diff --git a/web/src/app/shared/configuration/fields/fields.component.ts b/web/src/app/shared/configuration/fields/fields.component.ts index a12d37869c..a52c6246a7 100644 --- a/web/src/app/shared/configuration/fields/fields.component.ts +++ b/web/src/app/shared/configuration/fields/fields.component.ts @@ -25,7 +25,7 @@ import { IConfig, PanelOptions, FieldOptions } from '../types'; - + @@ -36,6 +36,7 @@ import { IConfig, PanelOptions, FieldOptions } from '../types'; export class ConfigFieldsComponent { dataOptions: (FieldOptions | PanelOptions)[] = []; form = new FormGroup({}); + rawConfig: IConfig; @Output() event = new EventEmitter<{ name: string; data?: any }>(); @@ -50,6 +51,7 @@ export class ConfigFieldsComponent { @Input() set model(data: IConfig) { + this.rawConfig = data; this.dataOptions = this.service.getPanels(data); this.form = this.service.toFormGroup(this.dataOptions); this.checkForm(); diff --git a/web/src/app/shared/configuration/group-fields/group-fields.component.html b/web/src/app/shared/configuration/group-fields/group-fields.component.html index 53bf5668c3..246140fe6c 100644 --- a/web/src/app/shared/configuration/group-fields/group-fields.component.html +++ b/web/src/app/shared/configuration/group-fields/group-fields.component.html @@ -18,7 +18,7 @@ - + diff --git a/web/src/app/shared/configuration/group-fields/group-fields.component.ts b/web/src/app/shared/configuration/group-fields/group-fields.component.ts index 1814d9076a..0217a576c0 100644 --- a/web/src/app/shared/configuration/group-fields/group-fields.component.ts +++ b/web/src/app/shared/configuration/group-fields/group-fields.component.ts @@ -16,7 +16,7 @@ import { MatSlideToggleChange } from '@angular/material/slide-toggle'; import { FieldService } from '../field.service'; import { FieldComponent } from '../field/field.component'; -import { FieldOptions, PanelOptions } from '../types'; +import { FieldOptions, PanelOptions, IConfig } from '../types'; @Component({ selector: 'app-group-fields', @@ -26,6 +26,7 @@ import { FieldOptions, PanelOptions } from '../types'; export class GroupFieldsComponent implements OnInit { @Input() panel: PanelOptions; @Input() form: FormGroup; + @Input() rawConfig: IConfig; @ViewChild('ep', { static: false }) expanel: MatExpansionPanel; checked = true; @@ -35,8 +36,8 @@ export class GroupFieldsComponent implements OnInit { constructor(private service: FieldService) {} ngOnInit(): void { - if (this.service.globalConfig.attr && this.service.globalConfig.attr[this.panel.name]) { - this.checked = this.service.globalConfig.attr[this.panel.name].active; + if (this.rawConfig.attr && this.rawConfig.attr[this.panel.name]) { + this.checked = this.rawConfig.attr[this.panel.name].active; this.checkFields(this.checked); } } @@ -45,12 +46,16 @@ export class GroupFieldsComponent implements OnInit { return 'options' in item && !item.hidden; } + getForm() { + return this.form.controls[this.panel.name]; + } + isAdvanced() { return this.panel.ui_options && this.panel.ui_options.advanced; } activeToggle(e: MatSlideToggleChange) { - this.service.globalConfig.attr[this.panel.name].active = e.checked; + this.rawConfig.attr[this.panel.name].active = e.checked; this.checked = e.checked; this.checkFields(e.checked); } diff --git a/web/src/app/shared/configuration/main/main.component.ts b/web/src/app/shared/configuration/main/main.component.ts index c5ad95dee7..5711452ef9 100644 --- a/web/src/app/shared/configuration/main/main.component.ts +++ b/web/src/app/shared/configuration/main/main.component.ts @@ -10,7 +10,7 @@ // See the License for the specific language governing permissions and // limitations under the License. import { animate, state, style, transition, trigger } from '@angular/animations'; -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, ViewChild } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, ViewChild, AfterViewInit } from '@angular/core'; import { ClusterService } from '@app/core'; import { ApiService } from '@app/core/api'; import { EventMessage, SocketState } from '@app/core/store'; @@ -43,7 +43,7 @@ import { FormGroup } from '@angular/forms'; ], changeDetection: ChangeDetectionStrategy.OnPush }) -export class ConfigComponent extends SocketListener implements OnInit { +export class ConfigComponent extends SocketListener implements OnInit, AfterViewInit { loadingStatus = 'Loading...'; config$: Observable; rawConfig: IConfig; @@ -85,6 +85,12 @@ export class ConfigComponent extends SocketListener implements OnInit { super.startListenSocket(); } + ngAfterViewInit(): void { + //Called after ngAfterContentInit when the component's view has been initialized. Applies to components only. + //Add 'implements AfterViewInit' to the class. + this.stub(); + } + isAdvanced(data: IConfig) { return data.config.some(a => a.ui_options && a.ui_options.advanced); } @@ -95,12 +101,12 @@ export class ConfigComponent extends SocketListener implements OnInit { fieldsEvents(e: { name: 'load'; data: { form: FormGroup } }) { if (e.name === 'load') { - this.stub(); + //this.stub(); } } get formValid() { - return this.service.form.valid; + return this.fields.form.valid; } history(flag: boolean) { @@ -108,18 +114,21 @@ export class ConfigComponent extends SocketListener implements OnInit { } filter(c: { advanced: boolean; search: string }) { - this.fields.dataOptions = this.service.filterApply(c); + this.service.filterApply(this.fields.dataOptions, c); this.stub(); } - /** + /** * change detection on manual - */ + */ stub() { - setTimeout(_ => { + //setTimeout(_ => { + + if (this.fields) { this.fields.checkForm(); this.cdRef.detectChanges(); - }, 0); + } + //}, 0); } socketListener(m: EventMessage) { @@ -145,11 +154,11 @@ export class ConfigComponent extends SocketListener implements OnInit { } save() { - const form = this.service.form; + const form = this.fields.form; if (form.valid) { this.saveFlag = true; - const config = this.service.parseValue(), + const config = this.service.parseValue(this.fields.form, this.rawConfig.config), attr = this.rawConfig.attr, description = this.tools.descriptionFormControl.value; diff --git a/web/src/app/shared/form-elements/field.directive.ts b/web/src/app/shared/form-elements/field.directive.ts index 562b647a44..114b6858fa 100644 --- a/web/src/app/shared/form-elements/field.directive.ts +++ b/web/src/app/shared/form-elements/field.directive.ts @@ -28,7 +28,7 @@ export class FieldDirective extends BaseDirective implements OnInit { } find() { - return this.form.controls[this.field.name]; + return this.form.controls[this.field.name] || this.form.controls[this.field.subname]; } get isValid() { From 12e221fd6728d3ba51db9c16df504560aea6d55f Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Tue, 18 Feb 2020 18:20:30 +0300 Subject: [PATCH 78/85] ADCM-1146 check view init --- web/src/app/core/services/detail.service.ts | 3 +- web/src/app/core/types/func.ts | 32 +++++++------------ .../actions/master/master.component.ts | 6 ++-- .../app/shared/configuration/field.service.ts | 26 ++++++--------- .../configuration/main/main.component.ts | 15 +++------ .../shared/form-elements/field.directive.ts | 2 +- 6 files changed, 33 insertions(+), 51 deletions(-) diff --git a/web/src/app/core/services/detail.service.ts b/web/src/app/core/services/detail.service.ts index 3896e37ad5..8d9aaf3f76 100644 --- a/web/src/app/core/services/detail.service.ts +++ b/web/src/app/core/services/detail.service.ts @@ -142,9 +142,10 @@ export class ClusterService { } reset(): Observable { - if (!this.Current || !this.worker) return EMPTY; + if (!this.Current) return EMPTY; const typeName = this.Current.typeName; return this.api.get(this.Current.url).pipe( + filter(_ => !!this.worker), map(a => { if (typeName === 'cluster') this.worker.cluster = { ...(a as Cluster), typeName }; this.worker.current = { ...a, typeName }; diff --git a/web/src/app/core/types/func.ts b/web/src/app/core/types/func.ts index 8d2fc51692..6fd017f230 100644 --- a/web/src/app/core/types/func.ts +++ b/web/src/app/core/types/func.ts @@ -10,10 +10,10 @@ // See the License for the specific language governing permissions and // limitations under the License. import { controlType } from '@app/shared/configuration/field.service'; -import { ConfigResultTypes, ConfigValueTypes, FieldStack } from '@app/shared/configuration/types'; +import { ConfigResultTypes, ConfigValueTypes } from '@app/shared/configuration/types'; +import { matchType } from '@app/shared/configuration/yspec/yspec.service'; import { InnerIssue, Issue } from './issue'; -import { matchType } from '@app/shared/configuration/yspec/yspec.service'; export function getPattern(name: string): RegExp { const fn = { @@ -138,25 +138,17 @@ export function randomInteger(max: number, min: number = 0): number { return Math.floor(min + Math.random() * (max + 1 - min)); } -/** - * - * - * @export - * @param {any[]} input - Input data - * @param {*} value - Form value - * @returns collection with inner properties - */ -export function parseValueConfig(input: FieldStack[], value: any) { - return input.reduce((p, a) => nameCheck(value, a, p), {}); -} +// export function parseValueConfig(input: FieldStack[], value: any) { +// return input.reduce((p, a) => nameCheck(value, a, p), {}); +// } -function nameCheck(value: any, a: FieldStack, p: {}) { - if (a.subname) { - if (!p.hasOwnProperty(a.name)) p[a.name] = {}; - p[a.name][a.subname] = checkValue(value[`${a.subname ? a.subname + '/' : ''}${a.name}`], a.type); - } else p[a.name] = checkValue(value[a.name], a.type); - return p; -} +// function nameCheck(value: any, a: FieldStack, p: {}) { +// if (a.subname) { +// if (!p.hasOwnProperty(a.name)) p[a.name] = {}; +// p[a.name][a.subname] = checkValue(value[`${a.subname ? a.subname + '/' : ''}${a.name}`], a.type); +// } else p[a.name] = checkValue(value[a.name], a.type); +// return p; +// } /** * Type casting after form editing diff --git a/web/src/app/shared/components/actions/master/master.component.ts b/web/src/app/shared/components/actions/master/master.component.ts index 460f502073..515258d8c5 100644 --- a/web/src/app/shared/components/actions/master/master.component.ts +++ b/web/src/app/shared/components/actions/master/master.component.ts @@ -11,13 +11,13 @@ // limitations under the License. import { Component, EventEmitter, OnInit } from '@angular/core'; import { ApiService } from '@app/core/api'; -import { parseValueConfig, IAction } from '@app/core/types'; +import { IAction } from '@app/core/types'; import { DynamicComponent, DynamicEvent, ServiceHostComponent } from '@app/shared'; +import { FieldService } from '@app/shared/configuration/field.service'; +import { ConfigFieldsComponent } from '@app/shared/configuration/fields/fields.component'; import { BaseDirective } from '../../../directives/base.directive'; -import { ConfigFieldsComponent } from '@app/shared/configuration/fields/fields.component'; import { ActionParameters } from '../actions.directive'; -import { FieldService } from '@app/shared/configuration/field.service'; @Component({ selector: 'app-master', diff --git a/web/src/app/shared/configuration/field.service.ts b/web/src/app/shared/configuration/field.service.ts index 4addbcdb6d..910c829002 100644 --- a/web/src/app/shared/configuration/field.service.ts +++ b/web/src/app/shared/configuration/field.service.ts @@ -25,8 +25,6 @@ export type controlType = 'boolean' | 'textbox' | 'textarea' | 'json' | 'passwor @Injectable() export class FieldService { - // globalConfig: IConfig; - constructor(private fb: FormBuilder, private spec: YspecService) {} isVisibleField = (a: ConfigOptions) => !a.ui_options || !a.ui_options.invisible; @@ -35,17 +33,13 @@ export class FieldService { isHidden = (a: FieldStack) => a.ui_options && (a.ui_options.invisible || a.ui_options.advanced); getPanels(data: IConfig): (FieldOptions | PanelOptions)[] { - // this.globalConfig = data; - if (data && data.config) { - const fo = data.config.filter(a => a.type !== 'group' && a.subname); //.map((a: FieldStack) => this.getFieldBy(a)); - //return data.config.filter(a => a.name !== '__main_info' && a.type === 'group').map(a => this.fillDataOptions(a, fo)); - // if (!a.subname) return this.checkYspec(this.getFieldBy(a)); + const fo = data.config.filter(a => a.type !== 'group' && a.subname); return data.config .filter(a => a.name !== '__main_info') .reduce((p, c) => { if (c.subname) return p; - if (c.type !== 'group') return [...p, this.getFieldBy(c)]; + if (c.type !== 'group') return [...p, this.checkYspec(this.getFieldBy(c))]; else return [...p, this.fillDataOptions(c, fo)]; }, []); } @@ -63,17 +57,17 @@ export class FieldService { c.name = c.subname; return c; }) + .map(b => this.checkYspec(b)) }; } - //checkYspec(a: FieldStack): FieldOptions | PanelOptions { - // a.name = a.subname || a.name; - // if (a.limits && a.limits.yspec) { - // this.spec.Root = a.limits.yspec; - // (a as IStructure).rules = this.spec.build(); - // } - // return a; - //} + checkYspec(a: FieldOptions): FieldOptions | PanelOptions { + if (a.limits && a.limits.yspec) { + this.spec.Root = a.limits.yspec; + (a as IStructure).rules = this.spec.build(); + } + return a; + } getFieldBy(item: FieldStack): FieldOptions { const params: FieldOptions = { diff --git a/web/src/app/shared/configuration/main/main.component.ts b/web/src/app/shared/configuration/main/main.component.ts index 5711452ef9..6baf8c7af5 100644 --- a/web/src/app/shared/configuration/main/main.component.ts +++ b/web/src/app/shared/configuration/main/main.component.ts @@ -10,7 +10,8 @@ // See the License for the specific language governing permissions and // limitations under the License. import { animate, state, style, transition, trigger } from '@angular/animations'; -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, ViewChild, AfterViewInit } from '@angular/core'; +import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, ViewChild, AfterViewChecked } from '@angular/core'; +import { FormGroup } from '@angular/forms'; import { ClusterService } from '@app/core'; import { ApiService } from '@app/core/api'; import { EventMessage, SocketState } from '@app/core/store'; @@ -24,7 +25,6 @@ import { ConfigFieldsComponent } from '../fields/fields.component'; import { HistoryComponent } from '../tools/history.component'; import { ToolsComponent } from '../tools/tools.component'; import { IConfig } from '../types'; -import { FormGroup } from '@angular/forms'; @Component({ selector: 'app-config-form', @@ -43,7 +43,7 @@ import { FormGroup } from '@angular/forms'; ], changeDetection: ChangeDetectionStrategy.OnPush }) -export class ConfigComponent extends SocketListener implements OnInit, AfterViewInit { +export class ConfigComponent extends SocketListener implements OnInit, AfterViewChecked { loadingStatus = 'Loading...'; config$: Observable; rawConfig: IConfig; @@ -85,9 +85,7 @@ export class ConfigComponent extends SocketListener implements OnInit, AfterView super.startListenSocket(); } - ngAfterViewInit(): void { - //Called after ngAfterContentInit when the component's view has been initialized. Applies to components only. - //Add 'implements AfterViewInit' to the class. + ngAfterViewChecked(): void { this.stub(); } @@ -101,7 +99,7 @@ export class ConfigComponent extends SocketListener implements OnInit, AfterView fieldsEvents(e: { name: 'load'; data: { form: FormGroup } }) { if (e.name === 'load') { - //this.stub(); + this.stub(); } } @@ -122,13 +120,10 @@ export class ConfigComponent extends SocketListener implements OnInit, AfterView * change detection on manual */ stub() { - //setTimeout(_ => { - if (this.fields) { this.fields.checkForm(); this.cdRef.detectChanges(); } - //}, 0); } socketListener(m: EventMessage) { diff --git a/web/src/app/shared/form-elements/field.directive.ts b/web/src/app/shared/form-elements/field.directive.ts index 114b6858fa..562b647a44 100644 --- a/web/src/app/shared/form-elements/field.directive.ts +++ b/web/src/app/shared/form-elements/field.directive.ts @@ -28,7 +28,7 @@ export class FieldDirective extends BaseDirective implements OnInit { } find() { - return this.form.controls[this.field.name] || this.form.controls[this.field.subname]; + return this.form.controls[this.field.name]; } get isValid() { From 3717e2ffd949247e7dd78b352a1d315d02f462bf Mon Sep 17 00:00:00 2001 From: Davidov Pavel Date: Wed, 19 Feb 2020 11:03:55 +0300 Subject: [PATCH 79/85] Check version --- web/src/app/app.component.ts | 37 ++++++++++++--------- web/src/app/core/services/config.service.ts | 15 +++++---- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/web/src/app/app.component.ts b/web/src/app/app.component.ts index 27977914f6..8a19a82302 100644 --- a/web/src/app/app.component.ts +++ b/web/src/app/app.component.ts @@ -28,7 +28,7 @@ import { State } from '@app/core/store'; import { select, Store } from '@ngrx/store'; -import { combineLatest, Observable, of } from 'rxjs'; +import { combineLatest } from 'rxjs'; import { filter, tap } from 'rxjs/operators'; @Component({ @@ -44,9 +44,9 @@ import { filter, tap } from 'rxjs/operators';