perf: 修改 v3

pull/8873/head
ibuler 2022-08-30 11:56:56 +08:00
parent 951d4e4e0d
commit 585f0c64cd
38 changed files with 293 additions and 104 deletions

View File

@ -6,7 +6,7 @@ from common.drf.serializers import GroupedChoiceSerailizer
from assets.models import Platform from assets.models import Platform
from assets.serializers import PlatformSerializer from assets.serializers import PlatformSerializer
from assets.const import AllTypes, Category from assets.const import AllTypes, Category
from assets.resources.platform import get_platform_methods from assets.playbooks.platform import filter_platform_methods
__all__ = ['AssetPlatformViewSet'] __all__ = ['AssetPlatformViewSet']
@ -43,14 +43,8 @@ class AssetPlatformViewSet(JMSModelViewSet):
def ops_methods(self, request, *args, **kwargs): def ops_methods(self, request, *args, **kwargs):
category = request.query_params.get('category') category = request.query_params.get('category')
tp = request.query_params.get('type') tp = request.query_params.get('type')
item = request.query_params.get('item') method = request.query_params.get('method')
methods = get_platform_methods() methods = filter_platform_methods(category, tp, method)
if category:
methods = list(filter(lambda x: x['category'] == category, methods))
if tp:
methods = list(filter(lambda x: x['type'] == tp, methods))
if item:
methods = list(filter(lambda x: x.get('method') == item, methods))
return Response(methods) return Response(methods)
def check_object_permissions(self, request, obj): def check_object_permissions(self, request, obj):

View File

@ -8,33 +8,20 @@ import django.db.models.deletion
def migrate_platform_set_ops(apps, *args): def migrate_platform_set_ops(apps, *args):
platform_model = apps.get_model('assets', 'Platform') platform_model = apps.get_model('assets', 'Platform')
Attr = namedtuple('ops', [
'su_enabled', 'su_method', 'domain_enabled',
'change_password_enabled', 'change_password_method',
'verify_account_enabled', 'verify_account_method',
'create_account_enabled', 'create_account_method',
])
default_ok = { default_ok = {
'su_enabled': True, 'su_enabled': True,
'su_method': 'sudo', 'su_method': 'sudo',
'domain_enabled': True, 'domain_enabled': True,
'change_password_enabled': True, 'change_password_enabled': True,
'change_password_method': 'change_password_ansible', 'change_password_method': 'change_password_linux',
'verify_account_enabled': True, 'verify_account_enabled': True,
'verify_account_method': 'verify_account_ansible', 'verify_account_method': 'verify_account_ansible',
'create_account_enabled': True,
'create_account_method': 'create_account_ansible',
} }
platform_ops_map = { platform_ops_map = {
'Linux': default_ok, 'Linux': {**default_ok, 'change_password_method': 'change_password_linux'},
'Windows': default_ok, 'Windows': {**default_ok, 'change_password_method': 'change_password_windows'},
'AIX': Attr( 'AIX': {**default_ok, 'change_password_method': 'change_password_aix'},
True, 'sudo', True,
True, 'change_password_ansible',
True, 'verify_account_ansible',
True, 'create_account_ansible'
)
} }
platforms = platform_model.objects.all() platforms = platform_model.objects.all()

View File

@ -0,0 +1,60 @@
import os
import yaml
from functools import partial
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
def check_platform_method(manifest):
required_keys = ['category', 'method', 'name', 'id']
less_key = set(required_keys) - set(manifest.keys())
if less_key:
raise ValueError("Manifest missing keys: {}".format(less_key))
return True
def get_platform_methods():
methods = []
for root, dirs, files in os.walk(BASE_DIR, topdown=False):
for name in dirs:
path = os.path.join(root, name)
rel_path = path.replace(BASE_DIR, '.')
if len(rel_path.split('/')) != 3:
continue
manifest_path = os.path.join(path, 'manifest.yml')
if not os.path.exists(manifest_path):
continue
with open(manifest_path, 'r') as f:
manifest = yaml.safe_load(f)
check_platform_method(manifest)
methods.append(manifest)
return methods
def filter_key(manifest, attr, value):
manifest_value = manifest.get(attr, '')
if manifest_value == 'all':
return True
if isinstance(manifest_value, str):
manifest_value = [manifest_value]
return value in manifest_value
def filter_platform_methods(category, tp, method):
methods = platform_ops_methods
if category:
methods = filter(partial(filter_key, attr='category', value=category), methods)
if tp:
methods = filter(partial(filter_key, attr='type', value=tp), methods)
if method:
methods = filter(lambda x: x['method'] == method, methods)
return methods
platform_ops_methods = get_platform_methods()
if __name__ == '__main__':
print(get_platform_methods())

View File

@ -0,0 +1,6 @@
id: change_password_mysql
name: Change password for MySQL
category: database
type: mysql
method: change_password

View File

@ -0,0 +1,5 @@
id: change_password_oracle
name: Change password for Oracle
method: change_password
category: database
type: oracle

View File

@ -0,0 +1,5 @@
id: change_password_postgresql
name: Change password for PostgreSQL
category: database
type: postgresql
method: change_password

View File

@ -0,0 +1,27 @@
- name: ping
ping:
#- name: print variables
# debug:
# msg: "Username: {{ account.username }}, Password: {{ account.password }}"
- name: Change password
user:
name: "{{ account.username }}"
password: "{{ account.password | password_hash('des') }}"
update_password: always
when: account.password
- name: Change public key
authorized_key:
user: "{{ account.username }}"
key: "{{ account.public_key }}"
state: present
when: account.public_key
- name: Verify password
ping:
vars:
ansible_user: "{{ account.username }}"
ansible_pass: "{{ account.password }}"
ansible_ssh_connection: paramiko

View File

@ -0,0 +1,10 @@
{% for account in accounts %}
- hosts: {{ account.asset.name }}
vars:
account:
username: {{ account.username }}
password: {{ account.password }}
public_key: {{ account.public_key }}
roles:
- change_password
{% endfor %}

View File

@ -0,0 +1,7 @@
id: change_password_sqlserver
name: Change password for SQLServer
version: 1
category: database
type: sqlserver
method: change_password

View File

@ -0,0 +1,27 @@
- name: ping
ping:
#- name: print variables
# debug:
# msg: "Username: {{ account.username }}, Password: {{ account.password }}"
- name: Change password
user:
name: "{{ account.username }}"
password: "{{ account.password | password_hash('des') }}"
update_password: always
when: account.password
- name: Change public key
authorized_key:
user: "{{ account.username }}"
key: "{{ account.public_key }}"
state: present
when: account.public_key
- name: Verify password
ping:
vars:
ansible_user: "{{ account.username }}"
ansible_pass: "{{ account.password }}"
ansible_ssh_connection: paramiko

View File

@ -0,0 +1,9 @@
id: change_password_example
name: Change password example
category: host
method: change_password
vars:
account:
username: test
password: teset123
public_key: test

View File

@ -0,0 +1,6 @@
#!/usr/bin/env python
#
"""
Will run with the args:
$0 $asset_json $account_json
"""

View File

@ -0,0 +1,10 @@
{% for account in accounts %}
- hosts: {{ account.asset.name }}
vars:
account:
username: {{ account.username }}
password: {{ account.password }}
public_key: {{ account.public_key }}
roles:
- change_password
{% endfor %}

View File

@ -0,0 +1,5 @@
id: change_password_aix
name: Change password for AIX
version: 1
category: host
method: change_password

View File

@ -0,0 +1,27 @@
- name: ping
ping:
#- name: print variables
# debug:
# msg: "Username: {{ account.username }}, Password: {{ account.password }}"
- name: Change password
user:
name: "{{ account.username }}"
password: "{{ account.password | password_hash('des') }}"
update_password: always
when: account.password
- name: Change public key
authorized_key:
user: "{{ account.username }}"
key: "{{ account.public_key }}"
state: present
when: account.public_key
- name: Verify password
ping:
vars:
ansible_user: "{{ account.username }}"
ansible_pass: "{{ account.password }}"
ansible_ssh_connection: paramiko

View File

@ -0,0 +1,10 @@
{% for account in accounts %}
- hosts: {{ account.asset.name }}
vars:
account:
username: {{ account.username }}
password: {{ account.password }}
public_key: {{ account.public_key }}
roles:
- change_password
{% endfor %}

View File

@ -0,0 +1,12 @@
id: change_password_linux
name: Change password for Linux
category: host
type:
- unix
- linux
method: change_password
vars:
account:
username: test
password: teset123
public_key: test

View File

@ -0,0 +1,10 @@
{% for account in accounts %}
- hosts: {{ account.asset.name }}
vars:
account:
username: {{ account.username }}
password: {{ account.password }}
public_key: {{ account.public_key }}
roles:
- change_password
{% endfor %}

View File

@ -0,0 +1,11 @@
id: change_password_local_windows
name: Change password local account for Windows
version: 1
method: change_password
category: host
type: windows
vars:
account:
username: test
password: teset123
public_key: test

View File

@ -0,0 +1,27 @@
- name: ping
ping:
#- name: print variables
# debug:
# msg: "Username: {{ account.username }}, Password: {{ account.password }}"
- name: Change password
user:
name: "{{ account.username }}"
password: "{{ account.password | password_hash('des') }}"
update_password: always
when: account.password
- name: Change public key
authorized_key:
user: "{{ account.username }}"
key: "{{ account.public_key }}"
state: present
when: account.public_key
- name: Verify password
ping:
vars:
ansible_user: "{{ account.username }}"
ansible_pass: "{{ account.password }}"
ansible_ssh_connection: paramiko

View File

@ -0,0 +1,6 @@
id: verify_account_ansible
name: Ansible ping
description: Ansible ping
category: host
type: all
method: verify_account

View File

@ -1,30 +0,0 @@
import os
import yaml
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
platform_ops_methods = None
def get_platform_methods():
methods = []
for root, dirs, files in os.walk(BASE_DIR, topdown=False):
for name in dirs:
path = os.path.join(root, name)
rel_path = path.replace(BASE_DIR, '.')
if len(rel_path.split('/')) != 3:
continue
manifest_path = os.path.join(path, 'manifest.yml')
if not os.path.exists(manifest_path):
continue
f = open(manifest_path, 'r')
try:
manifest = yaml.safe_load(f)
except yaml.YAMLError as e:
continue
methods.append(manifest)
return methods
if __name__ == '__main__':
print(get_platform_methods())

View File

@ -1,11 +0,0 @@
id: change_password_ansible
name: Change password using ansible
version: 1
description: 使用特权账号更改账号的密码
author: ibuler
method: change_password
vars:
account:
username: test
password: teset123
public_key: test

View File

@ -1,11 +0,0 @@
id: change_password_ansible
name: Change password using ansible
version: 1
description: 使用特权账号更改账号的密码
author: ibuler
method: change_password
vars:
account:
username: test
password: teset123
public_key: test

View File

@ -1,11 +0,0 @@
id: change_password_ansible
name: Change password using ansible
version: 1
description: 使用特权账号更改账号的密码
author: ibuler
method: change_password
vars:
account:
username: test
password: teset123
public_key: test

View File

@ -1,8 +0,0 @@
id: verify_account_ansible
name: Change password using ansible
version: 1
description: 使用特权账号更改账号的密码
author: ibuler
category: host
type: linux
method: verify_account

View File

@ -11,7 +11,8 @@ from .common import BaseAccountSerializer
class AccountSerializer( class AccountSerializer(
AccountTemplateSerializerMixin, AuthSerializerMixin, BulkOrgResourceModelSerializer AccountTemplateSerializerMixin, AuthSerializerMixin,
BulkOrgResourceModelSerializer
): ):
ip = serializers.ReadOnlyField(label=_("IP")) ip = serializers.ReadOnlyField(label=_("IP"))
asset_name = serializers.ReadOnlyField(label=_("Asset")) asset_name = serializers.ReadOnlyField(label=_("Asset"))

View File

@ -73,7 +73,6 @@ class AssetSerializer(JMSWritableNestedModelSerializer):
""" """
资产的数据结构 资产的数据结构
""" """
class Meta: class Meta:
model = Asset model = Asset
fields_mini = [ fields_mini = [

View File

@ -49,7 +49,6 @@ class PlatformSerializer(JMSWritableNestedModelSerializer):
'domain_enabled', 'domain_default', 'su_enabled', 'su_method', 'domain_enabled', 'domain_default', 'su_enabled', 'su_method',
'protocols_enabled', 'protocols', 'ping_enabled', 'ping_method', 'protocols_enabled', 'protocols', 'ping_enabled', 'ping_method',
'verify_account_enabled', 'verify_account_method', 'verify_account_enabled', 'verify_account_method',
'create_account_enabled', 'create_account_method',
'change_password_enabled', 'change_password_method', 'change_password_enabled', 'change_password_method',
'type_constraints', 'comment', 'charset', 'type_constraints', 'comment', 'charset',
] ]
@ -59,8 +58,8 @@ class PlatformSerializer(JMSWritableNestedModelSerializer):
'verify_account_method': {'label': '校验账号方式'}, 'verify_account_method': {'label': '校验账号方式'},
'create_account_enabled': {'label': '启用创建账号'}, 'create_account_enabled': {'label': '启用创建账号'},
'create_account_method': {'label': '创建账号方式'}, 'create_account_method': {'label': '创建账号方式'},
'change_password_enabled': {'label': '启用账号改密'}, 'change_password_enabled': {'label': '启用账号创建改密'},
'change_password_method': {'label': '账号改密方式'}, 'change_password_method': {'label': '账号创建改密方式'},
} }
def validate(self, attrs): def validate(self, attrs):

View File

@ -124,7 +124,7 @@ class ConfigCrypto:
if plaintext: if plaintext:
value = plaintext value = plaintext
except Exception as e: except Exception as e:
logger.error('decrypt %s error: %s', item, e) pass
return value return value
@classmethod @classmethod
@ -134,7 +134,7 @@ class ConfigCrypto:
secret_encrypt_key = os.environ.get('SECRET_ENCRYPT_KEY', '') secret_encrypt_key = os.environ.get('SECRET_ENCRYPT_KEY', '')
if not secret_encrypt_key: if not secret_encrypt_key:
return None return None
print('Info: Using SM4 to encrypt config secret value') print('Info: try using SM4 to decrypt config secret value')
return cls(secret_encrypt_key) return cls(secret_encrypt_key)