tasks.py 8.5 KB
Newer Older
baltery's avatar
baltery 已提交
1 2 3
# ~*~ coding: utf-8 ~*~
import json

baltery's avatar
baltery 已提交
4
from celery import shared_task
5 6
from django.core.cache import cache

baltery's avatar
baltery 已提交
7
from common.utils import get_object_or_none, capacity_convert, sum_capacity, encrypt_password, get_logger
baltery's avatar
baltery 已提交
8 9
from .models import SystemUser, AdminUser, Asset
from .const import ADMIN_USER_CONN_CACHE_KEY_PREFIX, SYSTEM_USER_CONN_CACHE_KEY_PREFIX
baltery's avatar
baltery 已提交
10 11


baltery's avatar
baltery 已提交
12 13 14 15 16
FORKS = 10
TIMEOUT = 60
logger = get_logger(__file__)


baltery's avatar
baltery 已提交
17 18
@shared_task
def update_assets_hardware_info(assets):
baltery's avatar
baltery 已提交
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
    """
    Using ansible api to update asset hardware info
    :param assets:  asset seq
    :return: result summary ['contacted': {}, 'dark': {}]
    """
    from ops.utils import run_adhoc
    name = "GET_ASSETS_HARDWARE_INFO"
    tasks = [
        {
            'name': name,
            'action': {
                'module': 'setup'
            }
        }
    ]
    hostname_list = [asset.hostname for asset in assets]
    result = run_adhoc(hostname_list, pattern='all', tasks=tasks,
                       name=name, run_as_admin=True)
    summary, result_raw = result.results_summary, result.results_raw
    for hostname, info in result_raw['ok'].items():
baltery's avatar
baltery 已提交
39
        if info:
baltery's avatar
baltery 已提交
40
            info = info[name]['ansible_facts']
baltery's avatar
baltery 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
        else:
            continue
        asset = get_object_or_none(Asset, hostname=hostname)
        if not asset:
            continue

        ___vendor = info['ansible_system_vendor']
        ___model = info['ansible_product_version']
        ___sn = info['ansible_product_serial']

        for ___cpu_model in info['ansible_processor']:
            if ___cpu_model.endswith('GHz'):
                break
        else:
            ___cpu_model = 'Unknown'
        ___cpu_count = info['ansible_processor_count']
        ___cpu_cores = info['ansible_processor_cores']
        ___memory = '%s %s' % capacity_convert('{} MB'.format(info['ansible_memtotal_mb']))
        disk_info = {}
        for dev, dev_info in info['ansible_devices'].items():
            if dev_info['removable'] == '0':
                disk_info[dev] = dev_info['size']
        ___disk_total = '%s %s' % sum_capacity(disk_info.values())
        ___disk_info = json.dumps(disk_info)

        ___platform = info['ansible_system']
        ___os = info['ansible_distribution']
68
        ___os_version = info['ansible_distribution_version']
baltery's avatar
baltery 已提交
69 70 71 72 73 74 75
        ___os_arch = info['ansible_architecture']
        ___hostname_raw = info['ansible_hostname']

        for k, v in locals().items():
            if k.startswith('___'):
                setattr(asset, k.strip('_'), v)
        asset.save()
baltery's avatar
baltery 已提交
76 77 78 79 80 81

    for hostname, task in summary['dark'].items():
        logger.warn("Update {} hardware info error: {}".format(
            hostname, task[name],
        ))

82
    return summary
baltery's avatar
baltery 已提交
83 84


baltery's avatar
baltery 已提交
85
@shared_task
86
def update_assets_hardware_period():
baltery's avatar
baltery 已提交
87 88 89 90
    """
    Update asset hardware period task
    :return:
    """
91 92 93 94 95
    assets = Asset.objects.filter(type__in=['Server', 'VM'])
    update_assets_hardware_info(assets)


@shared_task
baltery's avatar
baltery 已提交
96 97 98 99 100 101 102
def test_admin_user_connectability(admin_user):
    """
    Test asset admin user can connect or not. Using ansible api do that
    :param admin_user:
    :return:
    """
    from ops.utils import run_adhoc
baltery's avatar
baltery 已提交
103
    assets = admin_user.get_related_assets()
baltery's avatar
baltery 已提交
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
    hosts = [asset.hostname for asset in assets]
    tasks = [
        {
            "name": "TEST_ADMIN_CONNECTIVE",
            "action": {
                "module": "ping",
            }
        }
    ]
    result = run_adhoc(hosts, tasks=tasks, pattern="all", run_as_admin=True)
    return result.results_summary


@shared_task
def test_admin_user_connectability_period():
    # assets = Asset.objects.filter(type__in=['Server', 'VM'])
    admin_users = AdminUser.objects.all()
    for admin_user in admin_users:
        summary = test_admin_user_connectability(admin_user)

        cache.set(ADMIN_USER_CONN_CACHE_KEY_PREFIX + admin_user.name, summary, 60*60*60)
        for i in summary['contacted']:
            cache.set(ADMIN_USER_CONN_CACHE_KEY_PREFIX + i, 1, 60*60*60)

        for i in summary['dark']:
            cache.set(ADMIN_USER_CONN_CACHE_KEY_PREFIX + i, 0, 60*60*60)


baltery's avatar
baltery 已提交
132
@shared_task
baltery's avatar
baltery 已提交
133 134 135 136 137 138 139 140 141 142 143 144 145 146
def test_admin_user_connectability_manual(asset):
    from ops.utils import run_adhoc
    # assets = Asset.objects.filter(type__in=['Server', 'VM'])
    hosts = [asset.hostname]
    tasks = [
        {
            "name": "TEST_ADMIN_CONNECTIVE",
            "action": {
                "module": "ping",
            }
        }
    ]
    result = run_adhoc(hosts, tasks=tasks, pattern="all", run_as_admin=True)
    if result.results_summary['dark']:
baltery's avatar
baltery 已提交
147
        cache.set(ADMIN_USER_CONN_CACHE_KEY_PREFIX + asset.hostname, 0, 60*60*60)
baltery's avatar
baltery 已提交
148 149
        return False
    else:
baltery's avatar
baltery 已提交
150
        cache.set(ADMIN_USER_CONN_CACHE_KEY_PREFIX + asset.hostname, 1, 60*60* 60)
baltery's avatar
baltery 已提交
151 152 153 154 155 156 157 158 159 160 161
        return True


@shared_task
def test_system_user_connectability(system_user):
    """
    Test system cant connect his assets or not.
    :param system_user:
    :return:
    """
    from ops.utils import run_adhoc
baltery's avatar
baltery 已提交
162
    assets = system_user.get_clusters_assets()
baltery's avatar
baltery 已提交
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
    hosts = [asset.hostname for asset in assets]
    tasks = [
        {
            "name": "TEST_SYSTEM_USER_CONNECTIVE",
            "action": {
                "module": "ping",
            }
        }
    ]
    result = run_adhoc(hosts, tasks=tasks, pattern="all", run_as=system_user.name)
    return result.results_summary


@shared_task
def test_system_user_connectability_period():
    for system_user in SystemUser.objects.all():
        summary = test_system_user_connectability(system_user)
baltery's avatar
baltery 已提交
180
        cache.set(SYSTEM_USER_CONN_CACHE_KEY_PREFIX + system_user.name, summary, 60*60*60)
baltery's avatar
baltery 已提交
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219


def get_push_system_user_tasks(system_user):
    tasks = [
        {
            'name': 'Add user',
            'action': {
                'module': 'user',
                'args': 'name={} shell={} state=present password={}'.format(
                    system_user.username, system_user.shell,
                    encrypt_password(system_user.password),
                ),
            }
        },
        {
            'name': 'Set authorized key',
            'action': {
                'module': 'authorized_key',
                'args': "user={} state=present key='{}'".format(
                    system_user.username, system_user.public_key
                )
            }
        },
        {
            'name': 'Set sudoers',
            'action': {
                'module': 'lineinfile',
                'args': "dest=/etc/sudoers state=present regexp='^{0} ALL=' "
                        "line='{0} ALL=(ALL) NOPASSWD: {1}' "
                        "validate='visudo -cf %s'".format(
                    system_user.username,
                    system_user.sudo,
                )
            }
        }
    ]
    return tasks


baltery's avatar
baltery 已提交
220 221
PUSH_SYSTEM_USER_PERIOD_TASK_NAME = 'PUSH SYSTEM USER [{}] PERIOD...'
PUSH_SYSTEM_USER_TASK_NAME = 'PUSH SYSTEM USER [{}] ASSETS'
baltery's avatar
baltery 已提交
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247


def push_system_user(system_user, assets, name):
    from ops.utils import get_task_by_name, run_adhoc_object, \
        create_task, create_adhoc

    if system_user.auto_push and assets:
        task = get_task_by_name(name)
        if not task:
            task = create_task(name, created_by="System")
            task.save()
        tasks = get_push_system_user_tasks(system_user)
        hosts = [asset.hostname for asset in assets]
        options = {'forks': FORKS, 'timeout': TIMEOUT}

        adhoc = task.get_latest_adhoc()
        if not adhoc or adhoc.task != tasks or adhoc.hosts != hosts:
            adhoc = create_adhoc(task=task, tasks=tasks, pattern='all',
                                 options=options, hosts=hosts, run_as_admin=True)
        return run_adhoc_object(adhoc)


@shared_task
def push_system_user_period():
    logger.debug("Push system user period")
    for s in SystemUser.objects.filter(auto_push=True):
baltery's avatar
baltery 已提交
248
        assets = s.get_clusters_assets()
baltery's avatar
baltery 已提交
249 250 251

        name = PUSH_SYSTEM_USER_PERIOD_TASK_NAME.format(s.name)
        push_system_user(s, assets, name)
252

baltery's avatar
baltery 已提交
253

baltery's avatar
baltery 已提交
254 255 256 257 258 259 260 261
def push_system_user_to_assets_if_need(system_user, assets=None, asset_groups=None):
    assets_to_push = []
    system_user_assets = system_user.assets.all()
    if assets:
        assets_to_push.extend(assets)
    if asset_groups:
        for group in asset_groups:
            assets_to_push.extend(group.assets.all())
baltery's avatar
baltery 已提交
262

baltery's avatar
baltery 已提交
263 264 265 266 267 268 269 270 271
    assets_need_push = set(assets_to_push) - set(system_user_assets)
    if not assets_need_push:
        return
    logger.debug("Push system user {} to {} assets".format(
        system_user.name, ', '.join([asset.hostname for asset in assets_need_push])
    ))
    result = push_system_user(system_user, assets_need_push, PUSH_SYSTEM_USER_TASK_NAME)
    system_user.assets.add(*tuple(assets_need_push))
    return result