Full Code of CloudWise-OpenSource/OMP for AI

main 40afb5a4b9d1 cached
659 files
6.1 MB
1.6M tokens
4568 symbols
1 requests
Download .txt
Showing preview only (6,740K chars total). Download the full file or copy to clipboard to get everything.
Repository: CloudWise-OpenSource/OMP
Branch: main
Commit: 40afb5a4b9d1
Files: 659
Total size: 6.1 MB

Directory structure:
gitextract_kwjdxdir/

├── .gitignore
├── .pre-commit-config.yaml
├── LICENSE
├── README.md
├── UpdateLog.md
├── component/
│   ├── .gitkeep
│   ├── alertmanager/
│   │   └── .gitkeep
│   ├── grafana/
│   │   └── .gitkeep
│   ├── loki/
│   │   └── .gitkeep
│   └── prometheus/
│       └── .gitkeep
├── config/
│   ├── omp.yaml
│   ├── private_key.pem
│   ├── product.yaml
│   └── salt/
│       ├── master
│       ├── minion
│       ├── minion.d/
│       │   └── _schedule.conf
│       └── minion.template
├── data/
│   ├── .gitkeep
│   └── inspection_file/
│       └── .gitkeep
├── doc/
│   ├── app_publish.md
│   └── changelogs.md
├── logs/
│   └── .gitkeep
├── omp_server/
│   ├── app_store/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── app_store_filters.py
│   │   ├── app_store_serializers.py
│   │   ├── apps.py
│   │   ├── cmd_install_utils.py
│   │   ├── deploy_mode_utils/
│   │   │   ├── __init__.py
│   │   │   ├── base.py
│   │   │   ├── even_num.py
│   │   │   ├── mysql.py
│   │   │   ├── normal.py
│   │   │   ├── odd_num.py
│   │   │   ├── rocketmq.py
│   │   │   └── tengine.py
│   │   ├── deploy_role_utils/
│   │   │   ├── __init__.py
│   │   │   ├── hadoop.py
│   │   │   ├── mysql.py
│   │   │   └── redis.py
│   │   ├── high_availability_utils/
│   │   │   ├── __init__.py
│   │   │   └── hadoop.py
│   │   ├── install_exec.py
│   │   ├── install_executor.py
│   │   ├── install_utils.py
│   │   ├── new_install_serializers.py
│   │   ├── new_install_utils.py
│   │   ├── new_install_view.py
│   │   ├── post_install_utils/
│   │   │   ├── __init__.py
│   │   │   ├── base.py
│   │   │   ├── nacos.py
│   │   │   └── tengine.py
│   │   ├── service_splitting.py
│   │   ├── tasks.py
│   │   ├── tmp_exec_back_task.py
│   │   ├── upload_task.py
│   │   ├── urls.py
│   │   ├── views.py
│   │   └── views_for_install.py
│   ├── backups/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── backup_service.py
│   │   ├── backups_serializers.py
│   │   ├── backups_utils.py
│   │   ├── migrations/
│   │   │   └── __init__.py
│   │   ├── tasks.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── db_models/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_auto_20211202_1830.py
│   │   │   ├── 0003_host_init_status.py
│   │   │   ├── 0004_auto_20211203_1617.py
│   │   │   ├── 0005_auto_20211206_1723.py
│   │   │   ├── 0005_update_init_status.py
│   │   │   ├── 0006_merge_20211206_1833.py
│   │   │   ├── 0007_deploymentplan.py
│   │   │   ├── 0008_service_vip.py
│   │   │   ├── 0009_auto_20211228_1603.py
│   │   │   ├── 0010_auto_20220114_1830.py
│   │   │   ├── 0010_backuphistory_backupsetting.py
│   │   │   ├── 0011_auto_20220112_1607.py
│   │   │   ├── 0012_auto_20220112_1653.py
│   │   │   ├── 0013_merge_20220114_1838.py
│   │   │   ├── 0014_auto_20220121_1616.py
│   │   │   ├── 0015_executionrecord.py
│   │   │   ├── 0016_auto_20220125_1800.py
│   │   │   ├── 0017_selfhealinghistory_selfhealingsetting.py
│   │   │   ├── 0018_userloginlog_request_result.py
│   │   │   ├── 0019_toolexecutedetailhistory_toolexecutemainhistory_toolinfo_uploadfilehistory.py
│   │   │   ├── 0020_init_tools.py
│   │   │   ├── 0021_customscript.py
│   │   │   ├── 0022_alertrule_rule.py
│   │   │   ├── 0023_auto_20220225_1747.py
│   │   │   ├── 0024_auto_20220226_1300.py
│   │   │   ├── 0025_alertrule_forbidden.py
│   │   │   ├── 0026_alertrule_hash_data.py
│   │   │   ├── 0026_auto_20220303_1527.py
│   │   │   ├── 0027_merge_20220304_2000.py
│   │   │   ├── 0028_auto_20220304_2001.py
│   │   │   ├── 0029_auto_20230110_1739.py
│   │   │   ├── 0030_auto_20230711_1739.py
│   │   │   ├── 0031_auto_20230921_1128.py
│   │   │   └── __init__.py
│   │   ├── mixins.py
│   │   ├── models/
│   │   │   ├── __init__.py
│   │   │   ├── backup.py
│   │   │   ├── custom_metric.py
│   │   │   ├── email.py
│   │   │   ├── env.py
│   │   │   ├── execution.py
│   │   │   ├── host.py
│   │   │   ├── inspection.py
│   │   │   ├── install.py
│   │   │   ├── monitor.py
│   │   │   ├── product.py
│   │   │   ├── self_heal.py
│   │   │   ├── service.py
│   │   │   ├── threshold.py
│   │   │   ├── tool.py
│   │   │   ├── upgrade.py
│   │   │   ├── upload.py
│   │   │   └── user.py
│   │   ├── receivers/
│   │   │   ├── __init__.py
│   │   │   ├── execution_record.py
│   │   │   └── service.py
│   │   └── signals/
│   │       └── __init__.py
│   ├── dev_code.md
│   ├── dev_requirement.txt
│   ├── hosts/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── hosts_filters.py
│   │   ├── hosts_serializers.py
│   │   ├── tasks.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── inspection/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── filters.py
│   │   ├── get_prometheus_risk_data.py
│   │   ├── get_service_topology.py
│   │   ├── inspection_utils.py
│   │   ├── joint_json_report.py
│   │   ├── serializers.py
│   │   ├── tasks.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── manage.py
│   ├── omp_server/
│   │   ├── __init__.py
│   │   ├── asgi.py
│   │   ├── celery.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── promemonitor/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── alert_util.py
│   │   ├── alertmanager.py
│   │   ├── apps.py
│   │   ├── custom_script_serializers.py
│   │   ├── custom_script_views.py
│   │   ├── grafana_url.py
│   │   ├── grafana_views.py
│   │   ├── promemonitor_filters.py
│   │   ├── promemonitor_serializers.py
│   │   ├── prometheus.py
│   │   ├── prometheus_utils.py
│   │   ├── tasks.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── service_upgrade/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── filters.py
│   │   ├── handler/
│   │   │   ├── __init__.py
│   │   │   ├── base.py
│   │   │   ├── rollback_handler.py
│   │   │   └── upgrade_handler.py
│   │   ├── serializers.py
│   │   ├── tasks.py
│   │   ├── update_data_json.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── services/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── app_check/
│   │   │   ├── __init__.py
│   │   │   ├── conf_check.py
│   │   │   └── manage_ser_exec.py
│   │   ├── apps.py
│   │   ├── permission.py
│   │   ├── self_heal_filter.py
│   │   ├── self_heal_serializers.py
│   │   ├── self_heal_util.py
│   │   ├── self_heal_view.py
│   │   ├── self_healing.py
│   │   ├── services_filters.py
│   │   ├── services_serializers.py
│   │   ├── tasks.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── tests/
│   │   ├── __init__.py
│   │   ├── base.py
│   │   ├── mixin.py
│   │   ├── test_app_store/
│   │   │   ├── __init__.py
│   │   │   ├── install_data_source.py
│   │   │   ├── make_install_fake_data.py
│   │   │   ├── test_app_check.py
│   │   │   ├── test_app_store.py
│   │   │   ├── test_app_store_install.py
│   │   │   ├── test_app_store_upload.py
│   │   │   ├── test_execute_package_scan.py
│   │   │   ├── test_get_application_template.py
│   │   │   ├── test_install_executor.py
│   │   │   ├── test_new_install.py
│   │   │   └── test_upload_package.py
│   │   ├── test_hosts/
│   │   │   ├── __init__.py
│   │   │   ├── test_celery_tasks.py
│   │   │   └── test_hosts.py
│   │   ├── test_inspection/
│   │   │   ├── __init__.py
│   │   │   ├── inspection_mixin.py
│   │   │   ├── test_crontab.py
│   │   │   ├── test_history.py
│   │   │   ├── test_inspection_email.py
│   │   │   └── test_report.py
│   │   ├── test_promemonitor/
│   │   │   ├── __init__.py
│   │   │   ├── test_alert.py
│   │   │   ├── test_alertmanager.py
│   │   │   ├── test_celery_tasks.py
│   │   │   ├── test_email_config.py
│   │   │   ├── test_global_maintain.py
│   │   │   ├── test_grafana_url.py
│   │   │   ├── test_grafana_views.py
│   │   │   ├── test_instance_name_list.py
│   │   │   ├── test_instrument_panel.py
│   │   │   ├── test_monitor_agent_restart.py
│   │   │   ├── test_promemonitor_url.py
│   │   │   ├── test_prometheus.py
│   │   │   ├── test_prometheus_utils.py
│   │   │   ├── test_receive_alert.py
│   │   │   └── test_threshold_rw.py
│   │   ├── test_services/
│   │   │   ├── __init__.py
│   │   │   ├── test_service_actions.py
│   │   │   └── test_services.py
│   │   ├── test_users/
│   │   │   ├── __init__.py
│   │   │   ├── test_login.py
│   │   │   └── test_users.py
│   │   └── test_utils/
│   │       ├── __init__.py
│   │       ├── test_agent_util.py
│   │       ├── test_crontab_utils.py
│   │       ├── test_crypto.py
│   │       ├── test_monitor_agent.py
│   │       ├── test_public_utils.py
│   │       ├── test_salt_client.py
│   │       └── test_ssh.py
│   ├── tool/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── find_tools.py
│   │   ├── serializers.py
│   │   ├── tasks.py
│   │   ├── tests.py
│   │   ├── tool_filters.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── users/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── urls.py
│   │   ├── users_filters.py
│   │   ├── users_serializers.py
│   │   └── views.py
│   └── utils/
│       ├── __init__.py
│       ├── common/
│       │   ├── __init__.py
│       │   ├── exceptions.py
│       │   ├── paginations.py
│       │   ├── serializers.py
│       │   ├── urls.py
│       │   ├── validators.py
│       │   └── views.py
│       ├── exception_handler.py
│       ├── middleware_handler.py
│       ├── parse_config.py
│       ├── plugin/
│       │   ├── __init__.py
│       │   ├── agent_util.py
│       │   ├── captcha/
│       │   │   ├── __init__.py
│       │   │   └── captcha.py
│       │   ├── crontab_utils.py
│       │   ├── crypto.py
│       │   ├── install_ntpdate.py
│       │   ├── monitor_agent.py
│       │   ├── public_utils.py
│       │   ├── salt_client.py
│       │   ├── send_email.py
│       │   ├── ssh.py
│       │   └── synch_grafana.py
│       ├── prometheus/
│       │   ├── __init__.py
│       │   ├── create_html_tar.py
│       │   ├── prometheus.py
│       │   ├── target_host.py
│       │   ├── target_service.py
│       │   ├── target_service_arangodb.py
│       │   ├── target_service_beanstalk.py
│       │   ├── target_service_clickhouse.py
│       │   ├── target_service_elasticsearch.py
│       │   ├── target_service_flink.py
│       │   ├── target_service_func.py
│       │   ├── target_service_gotty.py
│       │   ├── target_service_grafana.py
│       │   ├── target_service_hadoop.py
│       │   ├── target_service_httpd.py
│       │   ├── target_service_ignite.py
│       │   ├── target_service_jvm_base.py
│       │   ├── target_service_kafka.py
│       │   ├── target_service_mysql.py
│       │   ├── target_service_nacos.py
│       │   ├── target_service_ntpd.py
│       │   ├── target_service_postgresql.py
│       │   ├── target_service_prometheus.py
│       │   ├── target_service_redis.py
│       │   ├── target_service_rocketmq.py
│       │   ├── target_service_tengine.py
│       │   ├── target_service_zookeeper.py
│       │   ├── thread.py
│       │   ├── update_threshold.py
│       │   └── utils.py
│       └── response_handler.py
├── omp_web/
│   ├── README.md
│   ├── config-overrides.js
│   ├── package.json
│   ├── public/
│   │   ├── index.html
│   │   └── pubKey.json
│   ├── src/
│   │   ├── App.js
│   │   ├── components/
│   │   │   ├── CustomBreadcrumb/
│   │   │   │   ├── index.js
│   │   │   │   ├── index.module.less
│   │   │   │   └── store/
│   │   │   │       ├── actionsCreators.js
│   │   │   │       ├── constants.js
│   │   │   │       ├── index.js
│   │   │   │       └── reduer.js
│   │   │   ├── OmpButton/
│   │   │   │   └── index.js
│   │   │   ├── OmpCollapseWrapper/
│   │   │   │   ├── index.js
│   │   │   │   ├── index.module.less
│   │   │   │   └── indexOld.js
│   │   │   ├── OmpContentNav/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── OmpContentWrapper/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── OmpDatePicker/
│   │   │   │   └── index.js
│   │   │   ├── OmpDrawer/
│   │   │   │   └── index.js
│   │   │   ├── OmpIframe/
│   │   │   │   └── index.js
│   │   │   ├── OmpMaintenanceModal/
│   │   │   │   └── index.js
│   │   │   ├── OmpMessageModal/
│   │   │   │   └── index.js
│   │   │   ├── OmpModal/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── OmpOperationWrapper/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── OmpProgress/
│   │   │   │   └── index.js
│   │   │   ├── OmpSelect/
│   │   │   │   └── index.js
│   │   │   ├── OmpStateBlock/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── OmpTable/
│   │   │   │   ├── components/
│   │   │   │   │   └── OmpTableFilter.js
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── OmpToolTip/
│   │   │   │   └── index.js
│   │   │   └── index.js
│   │   ├── config/
│   │   │   ├── requestApi.js
│   │   │   └── router.config.js
│   │   ├── index.js
│   │   ├── layouts/
│   │   │   ├── container/
│   │   │   │   └── container.js
│   │   │   ├── index.js
│   │   │   ├── index.module.less
│   │   │   ├── indexOld.js
│   │   │   └── store/
│   │   │       ├── actionsCreators.js
│   │   │       ├── constants.js
│   │   │       ├── index.js
│   │   │       └── reduer.js
│   │   ├── pages/
│   │   │   ├── AlarmLog/
│   │   │   │   ├── config/
│   │   │   │   │   └── columns.js
│   │   │   │   └── index.js
│   │   │   ├── AppStore/
│   │   │   │   ├── config/
│   │   │   │   │   ├── ApplicationInstallation.js
│   │   │   │   │   ├── BatchInstallationModal.js
│   │   │   │   │   ├── ComponentInstallation.js
│   │   │   │   │   ├── DeleteServerModal.js
│   │   │   │   │   ├── GetService.js
│   │   │   │   │   ├── GetServiceModal.js
│   │   │   │   │   ├── Installation/
│   │   │   │   │   │   ├── component/
│   │   │   │   │   │   │   ├── BasicInfoItem/
│   │   │   │   │   │   │   │   └── index.js
│   │   │   │   │   │   │   ├── DependentinfoItem/
│   │   │   │   │   │   │   │   ├── component/
│   │   │   │   │   │   │   │   │   ├── DeployInstanceRow.js
│   │   │   │   │   │   │   │   │   ├── DeployNumRow.js
│   │   │   │   │   │   │   │   │   ├── DeployRow.js
│   │   │   │   │   │   │   │   │   ├── JdkRow.js
│   │   │   │   │   │   │   │   │   ├── RenderArr.js
│   │   │   │   │   │   │   │   │   └── RenderNum.js
│   │   │   │   │   │   │   │   └── index.js
│   │   │   │   │   │   │   ├── InstallInfoItem/
│   │   │   │   │   │   │   │   ├── component/
│   │   │   │   │   │   │   │   │   └── InstallDetail.js
│   │   │   │   │   │   │   │   └── index.js
│   │   │   │   │   │   │   ├── ServiceConfigItem/
│   │   │   │   │   │   │   │   └── index.js
│   │   │   │   │   │   │   ├── ServiceDistributionItem/
│   │   │   │   │   │   │   │   ├── component/
│   │   │   │   │   │   │   │   │   └── HasInstallService.js
│   │   │   │   │   │   │   │   └── index.js
│   │   │   │   │   │   │   └── index.module.less
│   │   │   │   │   │   ├── index.js
│   │   │   │   │   │   ├── index.module.less
│   │   │   │   │   │   ├── steps/
│   │   │   │   │   │   │   ├── Step1.js
│   │   │   │   │   │   │   ├── Step2.js
│   │   │   │   │   │   │   ├── Step3.js
│   │   │   │   │   │   │   └── Step4.js
│   │   │   │   │   │   └── store/
│   │   │   │   │   │       ├── actionsCreators.js
│   │   │   │   │   │       ├── constants.js
│   │   │   │   │   │       ├── index.js
│   │   │   │   │   │       └── reduer.js
│   │   │   │   │   ├── ReleaseModal.js
│   │   │   │   │   ├── Rollback/
│   │   │   │   │   │   ├── content/
│   │   │   │   │   │   │   ├── component/
│   │   │   │   │   │   │   │   ├── RollbackDetail.js
│   │   │   │   │   │   │   │   └── RollbackInfoItem.js
│   │   │   │   │   │   │   └── index.js
│   │   │   │   │   │   ├── index.js
│   │   │   │   │   │   └── index.module.less
│   │   │   │   │   ├── ScanServerModal.js
│   │   │   │   │   ├── ServiceRollbackModal.js
│   │   │   │   │   ├── ServiceUpgradeModal.js
│   │   │   │   │   ├── Upgrade/
│   │   │   │   │   │   ├── content/
│   │   │   │   │   │   │   ├── component/
│   │   │   │   │   │   │   │   ├── UpgradeDetail.js
│   │   │   │   │   │   │   │   └── UpgradeInfoItem.js
│   │   │   │   │   │   │   └── index.js
│   │   │   │   │   │   ├── index.js
│   │   │   │   │   │   └── index.module.less
│   │   │   │   │   ├── card.js
│   │   │   │   │   ├── component/
│   │   │   │   │   │   └── RenderComDependence.js
│   │   │   │   │   ├── detail.js
│   │   │   │   │   ├── img.js
│   │   │   │   │   └── index.module.less
│   │   │   │   ├── index.js
│   │   │   │   ├── index.module.less
│   │   │   │   └── store/
│   │   │   │       ├── actionsCreators.js
│   │   │   │       ├── constants.js
│   │   │   │       ├── index.js
│   │   │   │       └── reduer.js
│   │   │   ├── BackupRecords/
│   │   │   │   ├── config/
│   │   │   │   │   └── columns.js
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── BackupStrategy/
│   │   │   │   ├── CustomModal.js
│   │   │   │   ├── StrategyModal.js
│   │   │   │   ├── config/
│   │   │   │   │   └── columns.js
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── DeploymentPlan/
│   │   │   │   ├── config/
│   │   │   │   │   ├── columns.js
│   │   │   │   │   └── models.js
│   │   │   │   └── index.js
│   │   │   ├── EmailSettings/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── ExceptionList/
│   │   │   │   ├── config/
│   │   │   │   │   └── columns.js
│   │   │   │   └── index.js
│   │   │   ├── HomePage/
│   │   │   │   ├── index.js
│   │   │   │   ├── index.module.less
│   │   │   │   └── warningList.js
│   │   │   ├── InstallationRecord/
│   │   │   │   ├── config/
│   │   │   │   │   └── ServiceUpgradeModal.js
│   │   │   │   ├── index.js
│   │   │   │   ├── indexOld.js
│   │   │   │   └── tabs/
│   │   │   │       ├── installation.js
│   │   │   │       ├── rollback.js
│   │   │   │       └── upgrade.js
│   │   │   ├── Login/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── LoginLog/
│   │   │   │   └── index.js
│   │   │   ├── MachineManagement/
│   │   │   │   ├── config/
│   │   │   │   │   ├── columns.js
│   │   │   │   │   └── modals.js
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── MonitoringSettings/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── PatrolInspectionRecord/
│   │   │   │   ├── config/
│   │   │   │   │   ├── columns.js
│   │   │   │   │   ├── detail.js
│   │   │   │   │   └── index.css
│   │   │   │   └── index.js
│   │   │   ├── PatrolStrategy/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── RuleCenter/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── RuleExtend/
│   │   │   │   └── index.js
│   │   │   ├── RuleIndicator/
│   │   │   │   └── index.js
│   │   │   ├── SelfHealingRecord/
│   │   │   │   ├── config/
│   │   │   │   │   └── columns.js
│   │   │   │   └── index.js
│   │   │   ├── SelfHealingStrategy/
│   │   │   │   ├── StrategyModal.js
│   │   │   │   ├── config/
│   │   │   │   │   └── columns.js
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── ServiceManagement/
│   │   │   │   ├── config/
│   │   │   │   │   └── columns.js
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── SystemLog/
│   │   │   │   └── index.js
│   │   │   ├── SystemManagement/
│   │   │   │   ├── index.js
│   │   │   │   ├── index.module.less
│   │   │   │   └── store/
│   │   │   │       ├── actionsCreators.js
│   │   │   │       ├── constants.js
│   │   │   │       ├── index.js
│   │   │   │       └── reduer.js
│   │   │   ├── TaskRecord/
│   │   │   │   └── index.js
│   │   │   ├── ToolExecution/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── ToolExecutionResults/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── ToolManagement/
│   │   │   │   ├── config/
│   │   │   │   │   ├── card.js
│   │   │   │   │   └── index.module.less
│   │   │   │   ├── detail/
│   │   │   │   │   ├── Readme.js
│   │   │   │   │   ├── index.js
│   │   │   │   │   └── index.module.less
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   └── UserManagement/
│   │   │       └── index.js
│   │   ├── react-app-env.d.ts
│   │   ├── router.js
│   │   ├── store_redux/
│   │   │   ├── reducer.js
│   │   │   └── reduxStore.js
│   │   └── utils/
│   │       ├── index.module.less
│   │       ├── request.js
│   │       └── utils.js
│   └── tsconfig.json
├── package_hub/
│   ├── .gitkeep
│   ├── _modules/
│   │   ├── __init__.py
│   │   ├── arangodb_check.py
│   │   ├── beanstalkd_check.py
│   │   ├── clickhouse_check.py
│   │   ├── elasticsearch_check.py
│   │   ├── flink_check.py
│   │   ├── get_agent_info.py
│   │   ├── gotty_check.py
│   │   ├── grafana_check.py
│   │   ├── hadoop_check.py
│   │   ├── host_check.py
│   │   ├── httpd_check.py
│   │   ├── ignite_check.py
│   │   ├── init_host.py
│   │   ├── inspection_common.py
│   │   ├── kafka_check.py
│   │   ├── minio_check.py
│   │   ├── mysql_bak.sh.tmp
│   │   ├── mysql_check.py
│   │   ├── nacos_check.py
│   │   ├── ntpd_check.py
│   │   ├── postgreSql_bak.sh.tmp
│   │   ├── postgresql_check.py
│   │   ├── prometheus_check.py
│   │   ├── rocketmq_check.py
│   │   ├── tengine_check.py
│   │   ├── tomcat_check.py
│   │   └── zookeeper_check.py
│   ├── back_end_verified/
│   │   └── .gitkeep
│   ├── custom_scripts/
│   │   ├── .gitkeep
│   │   └── template.py
│   ├── data_files/
│   │   └── .gitkeep
│   ├── front_end_verified/
│   │   └── .gitkeep
│   ├── grafana_dashboard_json/
│   │   ├──  21-rediscluster-xin-xi-mian-ban.json
│   │   ├── 1-zhu-ji-xin-xi-mian-ban.json
│   │   ├── 10-ignite-xin-xi-mian-ban.json
│   │   ├── 11-kafka-xin-xi-mian-ban.json
│   │   ├── 12-mysql-xin-xi-mian-ban.json
│   │   ├── 13-nacos-xin-xi-mian-ban.json
│   │   ├── 14-postgresql-xin-xi-mian-ban.json
│   │   ├── 15-redis-xin-xi-mian-ban.json
│   │   ├── 16-tengine-nginx-xin-xi-mian-ban.json
│   │   ├── 17-zookeeper-xin-xi-mian-ban.json
│   │   ├── 18-exporter-status.json
│   │   ├── 19-jvm-xin-xi-mian-ban.json
│   │   ├── 2-fu-wu-zhuang-tai-xin-xi-mian-ban.json
│   │   ├── 20-clickhousecluster-xin-xi-mian-ban.json
│   │   ├── 22-mysqlcluster-xin-xi-mian-ban.json
│   │   ├── 23-tenginecluster-nginx-xin-xi-mian-ban.json
│   │   ├── 24-victoriametrics-xin-xi-mian-ban.json
│   │   ├── 25-rocketmq-xin-xi-mian-ban.json
│   │   ├── 3-mian-ban-lie-biao.json
│   │   ├── 4-app-logs.json
│   │   ├── 5-arangodb-xin-xi-mian-ban.json
│   │   ├── 6-beanstalkdxin-xi-mian-ban.json
│   │   ├── 7-clickhouse-xin-xi-mian-ban.json
│   │   ├── 8-elasticsearch-xin-xi-mian-ban.json
│   │   └── 9-httpd-xin-xi-mian-ban.json
│   ├── openssl_upgrade/
│   │   └── upgrade_ssl.sh
│   ├── prometheus_rules_template/
│   │   ├── exporter_status_rule.yml
│   │   ├── node_data_rule.yml
│   │   ├── node_rule.yml
│   │   └── service_status_rule.yml
│   ├── reactor/
│   │   ├── auth.sls
│   │   ├── start.sls
│   │   └── stop.sls
│   ├── runners/
│   │   ├── agent_start.py
│   │   └── agent_stop.py
│   ├── template/
│   │   ├── app_publish_readme.md
│   │   ├── deployment.xlsx
│   │   ├── import_hosts_template.xlsx
│   │   ├── inspection_html/
│   │   │   ├── asset-manifest.json
│   │   │   ├── index.html
│   │   │   └── static/
│   │   │       ├── css/
│   │   │       │   ├── 2.8ca66de9.chunk.css
│   │   │       │   └── main.041ca26a.chunk.css
│   │   │       ├── js/
│   │   │       │   ├── 2.0ca9bd94.chunk.js
│   │   │       │   ├── 2.0ca9bd94.chunk.js.LICENSE.txt
│   │   │       │   ├── main.e4ade54a.chunk.js
│   │   │       │   └── runtime-main.da7bcbe2.js
│   │   │       └── media/
│   │   │           ├── index.02867153.less
│   │   │           ├── index.2041a1d4.less
│   │   │           ├── index.2f186d27.less
│   │   │           ├── index.32dc937e.less
│   │   │           ├── index.383af9c4.less
│   │   │           ├── index.51825487.less
│   │   │           ├── index.60c6e3ea.less
│   │   │           ├── index.67101e84.less
│   │   │           ├── index.68b48da1.less
│   │   │           ├── index.73987a8f.less
│   │   │           ├── index.8372475c.less
│   │   │           ├── index.85c775e4.less
│   │   │           ├── index.8c12967b.less
│   │   │           ├── index.976fe83e.less
│   │   │           ├── index.cae8fdaf.less
│   │   │           ├── index.d15ddbc9.less
│   │   │           ├── index.d61ddb9a.less
│   │   │           ├── index.e1e14bcc.less
│   │   │           ├── index.e90871b5.less
│   │   │           └── index.module.b57695f6.less
│   │   └── template.md
│   ├── tmp_end_verified/
│   │   └── .gitkeep
│   ├── tool/
│   │   ├── download_data/
│   │   │   └── .gitkeep
│   │   ├── folder/
│   │   │   └── .gitkeep
│   │   ├── tar/
│   │   │   └── .gitkeep
│   │   ├── upload_data/
│   │   │   └── .gitkeep
│   │   └── verify_tar/
│   │       └── .gitkeep
│   └── verified/
│       └── .gitkeep
├── salt/
│   ├── master
│   ├── minion
│   ├── minion.d/
│   │   └── _schedule.conf
│   └── minion.template
└── scripts/
    ├── cmd_manager
    ├── install.sh
    ├── omp
    ├── source/
    │   ├── __init__.py
    │   ├── add_readonly_user.py
    │   ├── cmd_install_entrance.py
    │   ├── cron
    │   ├── features.py
    │   ├── install_mysql_redis.py
    │   ├── install_or_update.py
    │   ├── omp_rollback.py
    │   ├── omp_salt_agent
    │   ├── omp_upgrade.py
    │   ├── repair_dirty_data.py
    │   ├── salt
    │   ├── salt_agent_manager
    │   ├── scan_tar_file.py
    │   ├── scan_tools.py
    │   ├── service_manager.py
    │   ├── tengine
    │   ├── uninstall_app_store.py
    │   ├── uninstall_services.py
    │   ├── update_conf.py
    │   ├── update_data.py
    │   ├── update_grafana.py
    │   ├── update_monitor_agent.py
    │   ├── upgrade_service.py
    │   ├── uwsgi
    │   └── worker
    └── uninstall.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
/omp_web/node_modules
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
#   For a library or package, you might want to ignore these files since the code is
#   intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
#   However, in case of collaboration, if having platform-specific dependencies or dependencies
#   having no cross-platform support, pipenv may install dependencies that don't work, or not
#   install all needed dependencies.
#Pipfile.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

### Example user template template
### Example user template

# IntelliJ project files
.idea
*.iml
out
gen

# General
.DS_Store
omp_web/.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon��

# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
/jon_test_files/
/package_hub/127.0.0.1/

temp
/package_hub/omp_monitor_agent.tar.gz


================================================
FILE: .pre-commit-config.yaml
================================================
default_stages: [commit]
repos:
  - repo: https://github.com/yingzi113/pre-commit-hooks
    rev: 5863e162f1bed1f63eeb716e77d622ff8e3d9af9
    hooks:
    - id: check-case-conflict
  - repo: https://github.com/pre-commit/mirrors-autopep8
    rev: v1.4.4
    hooks:
    - id: autopep8
      args: [-i, --global-config=.flake8, -v, --ignore=E402]
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v2.4.0
    hooks:
    - id: flake8
      args:
      - --ignore=E501,E402
      exclude: package_hub/_modules/init_host.py
    - id: check-docstring-first
    - id: trailing-whitespace
    - id: check-ast
    - id: check-json
    - id: check-yaml
exclude: migrations


================================================
FILE: LICENSE
================================================
                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.


================================================
FILE: README.md
================================================
# Readme
# OMP-运维管理平台
OMP(Operation Management Platform)是云智慧公司自主设计、研发的轻量级、聚合型、智能运维管理平台。是一款为用户提供便捷运维能力和业务管理的综合平台。具备运维一应俱全的功能,目的是提升运维自动化、智能化,提高运维效率,提升业务连续性和安全性。

# OMP设计初衷
## 目前运维面临的痛点:
- 主机环境多样性,难以统一管理:如:混合云、私有云、跨IDC、虚拟化、容器化等
- 业务变更难度较大,自动编排能力较低
- 业务状态监控,多平台难以数据联动
- 业务出现异常,难以实现故障自愈
- 业务运行状态,难以评估,更难以分析
- 运维知识匮乏,缺少专家指导及专家解决方案

运维管理平台(OMP)的设计初衷就是想打造一应俱全的运维平台,降低交付难度,提升运维自动化、智能化,提高运维效率,提升业务连续性和安全性。

# OMP核心功能
- **主机纳管**:纳管主机资源,实时监控主机运行状态,可在线管理、在线连接终端等
- **应用管理**:平台已内置常用基础组件,也支持符合标准的自研服务发布到应用商店,从而提供便捷的应用管理,如:安装部署、变更发布、弹性扩缩容、在线配置、优化等
- **应用监控**:涵盖标准监控、定制监控、链路监控、智能监控等多种业务场景,通过大数据智能测算,可感知未来趋势,将异常控制在发生前
- **故障自愈**:当业务系统出现异常或故障时,可按照预定的自愈策略进行故障治理,极大降低故障对业务影响,减少企业损失
- **状态巡检**:自动、手动进行业务指标、运行状态汇总,支持自动发送报告到指定邮箱
- **备份/恢复**:针对核心数据进行本地+异地备份,支持自动执行备份并将数据发送至指定邮箱,达到异地的存储效果,确保数据安全
- **精简工具**:提供运维常用工具、命令、脚本、SQL等,为日常运维操作提供便利,减少误操作、减低技术门槛,支持自行维护、扩充更多工具
- **权限管理**:针对不同用户、角色,进行权限控制,及操作审计

# 架构设计
![./doc/architecture.png](./doc/architecture.png)

## Demo

通过浏览器访问页面,访问入口为:http://omp.cloudwise.com/#/login    \
默认用户名:admin     \
默认密码:Yunweiguanli@OMP  \
每晚 00:00 将重置数据



# 使用 OMP
## 安装部署
当前OMP安装包内部包含了其使用的所有组件,建议将OMP部署在 /data/ 下,当前版本部署流程如下:   \
step0:下载解压安装包

```shell
tar -xvf omp_open-*.tar.gz -C /data
```

step1:编辑文件,检查环境配置

```shell
vim /data/omp/config/omp.yaml
```

注意:当前版本已携带mysql、redis安装,配置信息如下,如需修改请在安装前修改

```yaml
# redis相关配置
redis:
  host: 127.0.0.1
  port: 6380
  password: common123
# mysql相关配置
mysql:
  host: 127.0.0.1
  port: 3307
  username: common
  password: Common@123
```

step2:执行安装脚本
```shell
cd /data/omp && bash scripts/install.sh
# 注意1:执行后根据提示选择本机ip,如主机上存在多网卡多IP情况,需要根据业务需求自行判断使用哪个ip地址
# 注意2:当前执行操作的用户即为OMP中各个服务进程的运行用户,在以后的维护中,也应使用此用户进行操作
```

## 管理OMP

注意:如需停止 OMP 相关服务,请先执行 “停止 OMP 定时保活任务” 操作

```shell
# [服务名称] 值为: all 为对所有组件操作
# all|mysql|redis|tengine|uwsgi|worker|cron|salt|prometheus|alertmanager|grafana|loki
bash /data/omp/scripts/omp [服务名称] [status|start|stop|restart]
```

停止 OMP 定时保活任务:

```Apache
# 查看定时任务
crontab -e

# 删除或注释如下内容,否则定时任务会将 OMP 自动拉起
# */5 * * * * bash /data/omp/scripts/omp all start &>/dev/null
```

## 卸载OMP

omp节点上卸载操作如下:
```shell
bash /data/omp/scripts/uninstall.sh
```
## 升级 & 回滚 OMP

```shell
# 升级命令
bash cmd_manager omp_upgrade [必填参数:升级目标路径(如:/data/omp,注意此处路径末尾无/)] [选填参数:从某个断点处升级,默认开头]
# 例如
bash 升级包路径/scripts/cmd_manager omp_upgrade /data/omp(当前正在运行的旧安装路径)

# 回滚命令
bash cmd_manager omp_upgrade [必填参数:升级目标路径(如:/data/omp,注意此处路径末尾无/)] [选填参数:从某个断点处升级,默认开头]
# 例如
bash 升级包路径/scripts/cmd_manager omp_rollback /data/omp(当前正在运行的旧安装路径)
```

## 断点执行

常用于执行过程中某一步骤失败时,期望从失败步骤处再次执行时使用,正常情况无需考虑此参数,参数默认下标为0

升级回滚可以理解成为jenkins的pipliene 是分步骤执行的,当我们在某一个位置出现异常时,手动修复后通过错误节点再次进行时使用,而跳过之前已经升级(回滚)正确的步骤

```shell
# 升级流程顺序如下:
# PreUpdate, Mysql, Redis, Grafana, Tengine, OmpWeb, OmpServer, Python, PostUpdate
```



# 环境依赖

## 技术栈

### 后端技术栈

- Python 3.8.7
- Django 3.1.4
- Saltstack 3002.2
- Uwsgi 2.0.19.1

### 数据库

- mysql 5.7.37
- redis 6.2.7

### 前端技术栈

- Tengine 1.22.0
- React 17.0.1

### 监控技术栈

- Prometheus 2.25.1
- Alertmanager 0.24.0
- Grafana  9.3.8
- Loki 2.4.1
- Promtail 2.2.0

## 内置组件概览

| **组件名称** | **组件作用**                                     | **端口**     |
| ------------ | ------------------------------------------------ | ------------ |
| tengine      | 平台访问入口,代理前端页面及后端uwsgi程序        | 19001        |
| uwsgi        | web容器,用于提供 python Django 后端程序访问入口 | 19003        |
| salt         | 开源组件,服务器控制程序,提供主机 Agent 通信    | 19004、19005 |
| worker       | 异步任务、定时任务执行程序,有进程无端口         | -            |
| prometheus   | 开源组件,提供监控数据                           | 19011        |
| grafana      | 开源组件,提供监控面板                           | 19014        |
| alertmanager | 开源组件,提供日志告警                           | 19013、9094  |
| loki         | 开源组件,提供日志采集                           | 19012、9095  |
| redis        | 开源组件,提供缓存,消息队列                     | 6380         |
| mysql        | 开源组件,数据存储                               | 3307         |
| ntpd         | 开源组件,提供时间同步功能                       | 123(udp)   |



# 关于应用商店

## 如何制作一个OMP应用商店中的应用

[OMP 社区版-应用商店发布说明文档](./doc/app_publish.md)
> 内含
 - 基础组件打包规范
 - 应用服务打包规范
 - 目录和配置说明
 - postgreSql、redis、rocketmq等应用Demo

## 卸载应用商店中已经发布的应用

>已支持界面操作

```shell
export LD_LIBRARY_PATH=/data/omp/component/env/lib && /data/omp/component/env/bin/python3.8 /data/omp/scripts/source/uninstall_app_store.py --product 产品名称 --app_name 组件/服务名称 --version 版本
```

 已经部署服务实例的安装包,无法卸载

 参数说明:

1.  ***--version*** 缺省时,卸载所有版本
2.  卸载基础组件 ***--app_name 基础组件名称***
3.  卸载应用/产品  ***--product 应用/产品名称***
4.  卸载应用下指定服务 ***--product 应用/产品名称 --app_name 服务名称***





欢迎加入
获取更多关于OMP的技术资料,或加入OMP开发者交流群,可扫描下方二维码咨询

<img src="./doc/contact-us.png" width="600px" height="400px" />


================================================
FILE: UpdateLog.md
================================================
# 更新日志

------





## v0.1.0 (2021.11.30)
- 【仪表盘】
  - 全局状态概览
  - 当前异常信息展示
  - 各模块状态展示
- 【主机管理】
  - 主机纳管(添加、导入、编辑、维护、删除)
  - 主机自动监控、告警
- 【应用商店】
  - 组件、应用WEB发布、服务端自动发现
  - 组件、应用部署,自动编排解决依赖
- 【服务管理】
  - 服务管理(启动、停止、重启、删除)
  - 服务监控(监控、日志、告警、自愈)
- 【应用监控】
  - 实时展示处于异常的主机、服务信息,呼应仪表盘的异常清单
  - 告警历史记录查看,未读提醒,按添加检索
  - 支持监控组件地址自定义,便于对接现有监控平台
- 【状态巡检】
  - 支持主机巡检、组件巡检、深度分析,且支持导出
  - 支持定时自动执行巡检任务
- 【系统管理】
  - 用户账户管理
  - 支持全局维护模式,避免人为操作时误报



## v0.5.0 (2022.04.11)

- 【应用商店】
  - 组件、应用服务的升级及回滚
  - 应用服务的增量安装
- 【部署模板】
  - 支持通过部署模版实现批量部署
- 【应用监控】
  - 支持告警邮件配置,将告警信息发送至指定邮箱
- 【故障自愈】
  - 展示故障自愈记录
  - 支持监控到服务状态异常后自动进行重启
  - 支持设置服务自愈尝试次数
- 【指标中心】
  - 支持添加自定义告警指标规则
  - 添加自定义扩展采集指标
- 【数据备份】
  - 支持mysql、arangodb、postgreSql数据备份
  - 备份记录展示、下载、删除
  - 支持自定义保存路径、定时备份策略及邮件推送备份内容
- 【实用工具】
  - 内置部分运维实用小工具
  - 展示小工具执行过程、输出展示及生成文件下载
- 【系统管理】
  - 增加邮件管理,支持设置smtp邮件服务器作为全局邮件发件箱

- 【平台优化】
  - 优化主机纳管逻辑,增加纳管成功率,支持删除主机
  - 优化应用安装服务逻辑代码
  - 优化巡检逻辑
  - 优化部分前端页面显示及交互效果
- 【其他】
  - 修复已知bug




## v0.6.0 (2022.11.29)
- 升级内置基础组件和环境
  - alertmanager 升级至 v0.24.0
  - tengine 升级至 v1.22.0
  - 扩充内置环境中部分第三方库
  - 升级主机 Agent & 监控 Agent
- 优化小工具异步任务执行逻辑
- 更新 prometheus 和 loki 的配置
- 修复 grafana 面板中 mysql 显示异常问题
- 补充应用商店基础组件包:mysq、elasticsearch
- 组件包从代码库抽离,减少源码 & 包体量


## v0.7.0 (2022.12.30)
- 完善 OMP 管理脚本功能
  - 支持升级、回滚,支持断点重试
  - 支持命令行卸载应用商店已发布服务
- 内置 Redis 5.0.37 升级至 6.2.7
- 验证码登陆
- 修改密码长度异常问题


## v0.8.0 (2023.01.30)
- 新增监控功能
  - 产品http请求 5XX 错误
  - jvm 文件句柄使用率过高
  - 修复部分服务无法获取 cpu、内存问题
- 增加只读用户功能
- 修复添加主机提示已经存在问题
- 银河麒麟V10 ARM ,鲲鹏920 (ARM架构)2023.03.30

## v0.9.0 (2023.05.31)

- 内置Grafana版本升级至 9.3.8
- 主机/服务详情页面布局调整
- 主机/服务/安装/升级/回滚页面中文本溢出处理
- 支持通过前端界面方式卸载应用商店中已经发布的应用
- 更新readme文档

## v1.0.0 (2023.07.30)

- 新增功能【服务纳管】模块
- 重构【服务自愈】模块
- 新增 OOM 告警
- 更新部分 Grafana 面板
  - 服务面板: redis、victoriametrics、rocketmq
  - 集群面板: redis、clickhouse、mysql、tengine
- 修复 Grafana 无法登陆问题

## v1.1.0 (2023.09.30)

- 重构「数据备份」模块
- 支持多端口服务监控 & 更新文档
- 前端优化,步骤类交互型界面,刷新自动跳转
- 前端优化,消除部分冗余导入
- 修复bug:仪表盘异常清单类型缺失,环形统计图跳转增加类型过滤,nodeExporter、loki启动失败问题

================================================
FILE: component/.gitkeep
================================================


================================================
FILE: component/alertmanager/.gitkeep
================================================


================================================
FILE: component/grafana/.gitkeep
================================================


================================================
FILE: component/loki/.gitkeep
================================================


================================================
FILE: component/prometheus/.gitkeep
================================================


================================================
FILE: config/omp.yaml
================================================
# 全局用户, 自动解析当前操作用户
global_user: common
# 初始化时由用户输入本机的ip地址
local_ip: 10.0.1.160
# SSH执行命令超时时间,单位秒
ssh_cmd_timeout: 60
# SSH连通性校验超时时间,单位秒
ssh_check_timeout: 10
# 线程池最大workers
thread_pool_max_workers: 10
# redis相关配置
redis:
  host: 127.0.0.1
  port: 19034
  password: common123
# mysql相关配置
mysql:
  host: 127.0.0.1
  port: 19033
  username: common
  password: Common@123
# salt相关配置
salt_master:
  publish_port: 19004
  ret_port: 19005
  timeout: 30
# uwsgi的配置
uwsgi:
  socket: 127.0.0.1:19003
  processes: 4
  threads: 2
# tengine相关的配置
tengine:
  access_port: 19001
  runserver_port: 19002
# 登录token过期时间,天
token_expiration: 1
#grafana认证字段,无需修改
grafana_api_key: test
#grafana_auth
grafana_auth:
  # grafana admin auth
  grafana_admin_auth:
    username: admin
    plaintext_password: Yunweiguanli@OMP_123
  # grafana viewer auth
  grafana_viewer_auth:
    username: omp
    plaintext_password: Common@123
# 关联邮件设置,谨慎修改
alert_manager:
  # 是否开启发送邮件配置,默认不开启
  send_email: false
  # 发件人邮箱配置
  EMAIL_SEND: <发件人邮箱>
  # smtp服务器地址端口配置
  SMTP_SMARTHOST: <SMTP 服务器,比如 smtp.163.com:465>
  # 解释待定????
  SMTP_HELLO: 163.com
  # 发件人的用户名配置
  EMAIL_SEND_USER: <发件人的用户名>
  # 发件人邮箱秘钥
  EMAIL_SEND_PASSWORD: <发件人邮箱密钥>
  # 发送频率(同一条报警消息的发送频率,s、m、h对应 秒、分、小时)
  EMAIL_SEND_INTERVAL: 30m
  # 接收代号
  RECEIVER: commonuser
  # 收件人
  EMAIL_ADDRESS: <收件人邮箱>
  # webhook地址,仅在手动维护OMP各个组件时才可能用到,其他情况下不建议修改
  WEBHOOK_URL: http://127.0.0.1:19001/api/promemonitor/receiveAlert/
# prometheus basic auth
prometheus_auth:
  username: omp
  plaintext_password: Yunweiguanli@OMP_123
  ciphertext_password: $2b$12$R8WlKOEV2M9iBjEhnWQORepigbQoD1D/rAyEXwIu/aS5t94deTVDu
# 监控使用相关端口配置
monitor_port:
  # server各个端口
  prometheus: 19011
  loki: 19012
  alertmanager: 19013
  grafana: 19014
  # agent端各个端口配置
  blackboxExporter: 19015
  promtail: 19016
  nodeExporter: 19017
  processExporter: 19018
  mysqlExporter: 19019
  redisExporter: 19020
  kafkaExporter: 19021
  zookeeperExporter: 19022
  clickhouseExporter: 19023
  postgreSqlExporter: 19024
  beanstalkdExporter: 19025
  tengineExporter: 19026
  elasticsearchExporter: 19027
  httpdExporter: 19028
  igniteExporter: 19029
  rocketmqExporter: 19032
  # arangodb与nacos没有单独的exporter,使用的是arangodb和nacos的原生自带接口
  arangodbExporter: 18119
  nacosExporter: 18117
  monitorAgent: 19031
# Loki相关配置
loki_config:
  # promtail采集日志文件名等级过滤 [debug, info, warn, error, all]
  scrape_log_level: error

# 基础及公共组件间的等级划分,不要将自研服务类的服务放入下面的配置
# 用于控制服务安装过程中的执行顺序、服务的启停控制顺序
# 安装时顺序从小到大执行,同级别并发执行
basic_order:
  0:
    - jdk
    - safeRM
    - tengine
    - mysql
    - comLib
    - redis
    - arangodb
    - minio
    - postgreSql
    - prometheus
    - pushgateway
    - mongodb
    - nodejs
    - beanstalk
  1:
    - keepalived
    - httpd
    - elasticsearch
    - zookeeper
    - rocketmq
    - wkhtmltox
    - tomcat
    - jkbPhp
  2:
    - nacos
    - xxlJob
    - kafka
    - clickhouse
    - hadoop
  3:
    - flink
    - aopsUtils
    - filebeat
    - victoriaMetrics
    - sentinel
# 自愈周期内服务key的存活时常 min
health_redis_timeout: 60
# 单次health接口检测最大次数
health_request_count: 10
# 单次health接口请求停留时常 s
health_request_sleep: 6
# 模板安装下,基础组件集群模式个数的严格校验
template_cluster_check: true
#服务发现脚本,纳管自定义排查脚本
service_discovery:
backup_service:
  - mysql
  - postgreSql

================================================
FILE: config/private_key.pem
================================================
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAwv4dqlvcYtrPJsCL/VuX0u4FZm2E0du1m01gUnp3afSkx+u2
GTXptpS7dNfTLguu1HjJUzkEIGaJGG/x/PR2Zs6I/UmIFWj6tdmfBBlrVRETnm8t
CAdO9/1zjzz4wB2yuHduBK6TYwhXfZOCg3LOj+QVpUYqyq3lqjPN+C6QbFzgk8Fw
MHr+R3OzZe9nsaNZOHRbSmu6NU5zkIdnScQwIiWIe9nZMpoTUe45FtYPj7SHiCIt
DOtbXGbyNOP5k5RhIQtJiEJgVOzGeRSaQAj6UfLClsa43ZXfXIZ+BfOO8GZBXmHe
RHRs/Prw3Io4n0gXKpgrd6MxwfpoxmXEyoRUGwIDAQABAoIBAQCBjcL6CFSSHZ0a
uz2HlQ53p4tQ9Z0Urayoxa0kv5eNf2zoI5T2hRqGI6W0yRzXcA21v5bLw4sZV+bo
pKAcF/R+8+SSnQNcbkZ9Al0jpRvqBhGJ54X82pY+MFhSKAmB43l2FGu1kqP8XXN7
zMEfQu05Lyquh8MwrH92KTtFFPMB+z5BQqukXbZxhkVjEEuDtfvHyw5hQkv4PtM8
Z+pd9Wh7/WMOq7dJn6nM+TVWQjz+nqsulCEHZ1oj2m4xk57b4QP9wm0DNe0k/bo5
6b7U/2jvtLeqhFbN2hp1fzHpqo4hDZTuYv9lBFlLGMnKPoppi+oYW8APmy123DCn
mWmKn3oJAoGBAOqKMRzLCGytbW+qeFhJgohhNnuYxRV5fzG5EUbOb8zO2nZO5QUw
hJApWDW/mOIvezr53UgLvadw9pnJdDQoQX8gxBX6j6eWbJvXwDU+pBw9Nl3U0ZTZ
Mu8TDy1k/Up59B5BwUInDX2klPJQI/vjf9KoSKXinBbXRkKURq+fMi1lAoGBANTV
lHWegOdKTzh9PDGbNcQ7KpO89WmLSJQXR54UsOs4x1Kcn0kOWTKV6piPJbAsGzXR
ucs9FfcQukDL/JabEeH0k3NedXCwR43SMTby7f1Sl+8nWdyu4Rf5Z4/iZq+JrbYu
bJ10ijbnpVCBQxrZ1ce88fyF56mbG0wry4IljyN/AoGBANQed5ya49umXjuH6Z+v
nCbMBQJzgIuTfr3xqvZm7iZFTr+BSxAOeVYIjobN6e9nEgScxszKEZTGTcF4uWgS
oGnhsHZQTmw7V676yhNdu/7uPaVPPN1qMu6WRjvAAnTBJ0/WGHtD5qejmjIs2N6P
OqPDHzEoahMeT6UXhXaAfFkhAoGADB3YpNWQOxqk5e9jROO0LOa9ZsnEIu0WBbBJ
mHtPEyUZW9+kxdD2TQXx5BuKJrxsFCVLcYGZxYYDRHsYdy5+1yFIX7IJ949hk3Za
7OjpmZlhIvFXkVO3ZtkBB1T5SZcJ96wu7MvcroGDjNC/FEFAhW2BTUIGTUaSSETa
Ah/HRVsCgYEAuoJK9FDdCDsZmAfXSo4T3JtGx1yvKQ1tFCREC2CEQ98S2aEc0tRZ
CvUUresVdN1AuxtYVDxUOtZPD5GUCrgR+z4heZNi25j6mCf51NAgnaV170sAOOn6
FjRXOYf0UFAo1eGZjsBp4bQdmdXxynzuW2jbNRxw8mZlHCBBx5jb1O8=
-----END RSA PRIVATE KEY-----


================================================
FILE: config/product.yaml
================================================
# 使用配置文件的方式更新产品的yaml,留出可更改接口
# 更新安装参数,如下安装参数在安装过程中会进行更改替换
install:
  nacos:
    - name: "租户类型1单2多3saas"
      key: "deploy_type"
      default: "1"
      editable: true
# 更新端口配置,如下端口在安装过程中会更新到端口中
ports:
  testService:
    - name: 服务端口
      protocol: TCP
      key: service_port
      default: 18125


================================================
FILE: config/salt/master
================================================
interface: 0.0.0.0
publish_port: 19004
ret_port: 19005
user: root
enable_ssh_minions: False
presence_events: True
auto_accept: True
timeout: 30
root_dir: /data/omp/data/salt
conf_file: /data/omp/config/salt/master
file_roots:
  base:
    - /data/omp/package_hub
file_recv: True
file_recv_max_size: 524288



================================================
FILE: config/salt/minion
================================================
master: ${MASTER_IP}
master_port: ${MASTER_PORT}
user: ${USER}
id: ${AGENT_ID}
root_dir: ${AGENT_DIR}/data/salt
conf_file: ${AGENT_DIR}/config/salt/minion


================================================
FILE: config/salt/minion.d/_schedule.conf
================================================
schedule:
  __mine_interval: {enabled: true, function: mine.update, jid_include: true, maxrunning: 2,
    minutes: 60, return_job: false, run_on_start: true}


================================================
FILE: config/salt/minion.template
================================================
master: ${MASTER_IP}
master_port: ${MASTER_PORT}
user: ${USER}
id: ${AGENT_ID}
root_dir: ${AGENT_DIR}/data/salt
conf_file: ${AGENT_DIR}/config/salt/minion


================================================
FILE: data/.gitkeep
================================================


================================================
FILE: data/inspection_file/.gitkeep
================================================


================================================
FILE: doc/app_publish.md
================================================
# OMP 社区版-应用商店发布说明文档

[TOC]

## 1. 说明

用户可以在应用商店发布“基础组件”与“应用服务”两个维度的产品,在区分上,应用服务可以理解为完整的提供某一类服务的产品,产品内部可由一个或多个“服务”组成 ,比如gitlab、jenkins等。基础组件的角色更多是作为其他完成产品的一部分存在,以完成产品的某些功能需求,如mysql、redis等。

## 2. 基础组件打包规范

注:用户在发布基础组件安装包时,需按照以下规范打包上传才可以正常发布

### 2.1. 目录规范

以MySQL服务为例,需将涉及到的文件统一放在 mysql目录下,目录名称与该服务名称保持一致,目录中需要提供与该目录名称一致的配置文件(如:mysql.yaml)、产品图标(如:mysql.svg)  和其他所需文件(如安装脚本等)

**示例:**

```shell
$ tree ./mysql -L 2
./mysql                 # 目录名称,请与组件名称一致
├── mysql.svg           # 平台展示组件图标,请使用 “组件名称.svg ” 命名,与目录名称保持一致
├── mysql.yaml          # 组件配置文件, 记录该组件安装、升级等所需信息, 请使用 “组件名称.yaml” 命名,与目录名称保持一致
└── scripts             # 组件的安装、启动等控制脚本,该脚本在安装时会调用
│   ├── init.py         # 初始化脚本
│   ├── install.py      # 组件安装脚本
│   ├── mysql           # 组件启动、停止控制脚本,建议与服务名称一致
│   ├── mysql_backup.py # 其他动作脚本,如备份等
```

**备注:**

1. 组件图标请使用svg格式图片,如不添加会显示平台缺省图标;
2. 确保目录名称(mysql)、配置文件(mysql.yaml) 、图标(mysql.svg) 名称统一, 上传安装包时,平台将根据名称校验对应文件合法性,如名称不一致,可能会导致校验不通过等问题;
3. 确保安装包解压后是一个整体目录

### 2.2. 压缩包命名规范

请使用 `{name}-{version}-{others}-{package_md5}.tar.gz`  格式进行打包命名

1. name:   安装包名称,建议字符:  `英文`  `数字`   `_`
2. version: 安装包版本,建议字符:  `英文` `数字` `_`   `.`
3. others:  其他信息,建议字符:  `英文` `数字` `_`   `.`
4. package_md5:  安装包MD5 值

例如:`mysql-5.7.31-beta-8e955b24fefe7061eb79cfc61a9a02a1.tar.gz`

```shell
$ tar czf mysql-5.7.31.tar.gz mysql
$ md5sum mysql-5.7.31.tar.gz
8e955b24fefe7061eb79cfc61a9a02a1
$ mv mysql-5.7.31.tar.gz mysql-5.7.31-8e955b24fefe7061eb79cfc61a9a02a1.tar.gz
```

### 2.3.  配置文件(yaml)说明

平台预留KEY值(该KEY值存在指定定义,请准确使用):

| KEY          | 说明         | 备注                                   |
| ------------ | ------------ | -------------------------------------- |
| service_port | 服务端口     | 供其他程序连接的端口号                 |
| base_dir     | 应用安装目录 |                                        |
| log_dir      | 应用日志目录 | 服务的日志采集会采集该目录下*.log 文件 |
| data_dir     | 应用数据目录 |                                        |
| username     | 用户名       |                                        |
| password     | 密码         |                                        |

```yaml
# 类型定义,发布基础组件时 ,指定类型为 component (类型:string)
kind: component
# 组件在平台显示的名称,请与组件目录名称保持一致,建议字符:英文、数字、_ (类型:string)
name: mysql
# 上传后显示的组件版本,建议字符: 数字、字母、_ 、. (类型:string)
version: 5.7.31
# 组件描述信息,建议长度256字符之内,请针对组件书写贴切的描述文字 (类型:string)
description: "MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。"
# 组件所属标签,请针对组件功能设置准确标签,平台会针对该标签对组件进行分类,(类型:list[string,string...])
labels:
  - 数据库
# 指定该服务安装后是否需要启动 (类型:boolean)
auto_launch: false
# 指定组件是否为基础环境组件,如 jdk, 该类组件以基础环境方式安装 (类型:boolean)
base_env: flase
# 定义组件所需端口号,如不启用端口,可留空 (类型:list[map,map...])
ports:
    # 端口描述名称,用户在安装时会以该名称显示表单内容(类型:string)
  - name: 服务端口
    # 端口协议,支持 TCP/UDP
    protocol: TCP
    # 端口英文描述名称,该key会传入到安装脚本中 (类型: string)支持(英文、数字、_)
    key: service_port  # 注:service_port 为保留关键词,表示 为 提供服务的端口
    # 组件的默认端口号,在安装时,会以该值填入表单中(类型: int)
    default: 3306
# 组件监控相关配置,定义该组件在安装后如何监控 ,如果不需要监控可留空 (类型: map)
monitor:
  # 监控进程名称,如“mysqld”,平台在发现mysqld进程不存在后,会发送告警提醒 ,不需要监控可留空(类型:string)
  process_name:  "mysqld"
  # 监控端口号,请根据 ports 中的变量设置,不需要监控可留空 (类型: {string})
  metric_port: {service_port}
---
# 设置集群模式方式,如果组件需要支持多种方式安装,可以在该字段中定义,如只支持单个实例安装,可留空(类型:map[list[map,map...]])
deploy:
  # 定义单实例模式安装 (类型:list[map,map...])
  single:
      # 部署方式的中文描述名称,该值会在表单中选择集群模式时显示 (类型:string)
    - name: 单实例
      # 该模式的key值 (类型:string)
      key: single
  # 定义多种集群模式安装 (类型:list[map,map...])
  complex:
      # 部署方式的中文描述名称,该值会在表单中选择集群模式时显示 (类型:string)
    - name: 主从模式
      # 该模式的key值 (类型:string)
      key: master_slave
      # 集群节点设置 (类型: map)
      nodes:
        # 初始节点数量 (类型:int)
        start: 2
        # 增加节点步长 (类型:int)
        step: 1
# 定义该组件安装所需依赖组件名称与版本,如不需其他组件依赖,可留空 (类型: list[map,map..])
#例:
#dependencies:
#  - name: jdk
#    version: 8u223
dependencies:
# 该组件所需最小资源需求 (类型:map)
resources:
  # cpu最小需求 ,1000m 表示 1核  (类型:string)
  cpu: 1000m
  # 内存最小需求, 500m 表示 500兆内存 (类型:string)
  memory: 500m

---
# 定义安装组件时所需参数,该参数会传入到 安装脚本中 (类型:list[map,map...])
install:
    # 传入参数中文描述名称,该名称会在用户安装组件时显示到表单中 (类型: string)
  - name: "安装目录"
    # 传入参数key值,会将该key与值 传入到安装脚本中 (类型:string)
    key: base_dir
    # 上面key默认值 (类型: stirng)
    default: "{data_path}/mysql"  # 注: {data_path} 为主机数据目录占位符,请勿使用其他代替
  - name: "数据目录"
    key: data_dir
    default: "{data_path}/mysql/data"
  - name: "日志目录"
    key: log_dir
    default: "{data_path}/mysql/log"
  - name: "用户名"
    key: username
    default: root
  - name: "密码"
    key: password
    default: "123456"
# 程序控制脚本与服务目录的相对路径 (类型:map)
control:
  # 启动脚本路径,如没有可留空 (类型:string)
  start: "./scripts/mysql start"
  # 停止脚本路径,如没有可留空 (类型:stirng)
  stop: "./scripts/mysql stop"
  # 重启脚本路径,如没有可留空 (类型:stirng)
  restart: "./scripts/mysql restart"
  # 重载脚本路径,如没有可留空 (类型:stirng)
  reload:
  # 安装脚本路径,必填 (类型:stirng)
  install: "./scripts/install.py"
  # 初始化脚本路径,必填 (类型:stirng)
  init:  "./scripts/init.py"
```

### 2.4. 安装脚本编写说明

在安装包成功发布后,可通过平台进行安装,平台会调用配置文件中指定的安装脚本进行程序安装,平台将会把安装脚本所需参数以如下形式进行传参,需要脚本在编写时对此进行支持。

传参示例:

```shell
$ python ./scripts/install.py --local_ip 192.168.1.2 --data_json /data/LKJD82JDL.json
```

其中 local_ip 为安装主机的IP地址,data_json为安装所需数据文件路径

安装脚本需要根据data_json内数据进行组件的安装、替换其他文件内的占位符

data.json示例:

```json
[
    {
        "name":"nacos",
        "ip":"1.1.1.1",
        "version":"2.0.1",
        "ports":[
            {
                "key":"service_port",
                "name":"xxx端口",
                "default":8001
            }
        ],
        "install_arg":[
            {
                "key":"base_dir",
                "name":"服务目录",
                "default":"/data/app/nacos"
            },
            {
                "key":"data_dir",
                "name":"数据目录",
                "default":"/data/appData/nacos"
            },
            {
                "key":"username",
                "name":"用户名",
                "default":"admin"
            },
            {
                "key":"password",
                "name":"密码",
                "default":"admin123"
            }
        ],
        "deploy_mode":{

        },
        "cluster_name":"",
        "instance_name":"nacos-1",
        "dependence":[
            {
                "name":"mysql",
                "instance_name":"mysql-100",
                "cluster_name":"mysql-JDLK3KA"
            }
        ]
    },
    {
        "name":"mysql",
        "ip":"192.1.2.3",
        "version":"5.0.1",
        "ports":[
            {
                "key":"service_port",
                "name":"服务端口",
                "default":10601
            }
        ],
        "install_arg":[
            {
                "key":"base_dir",
                "name":"服务目录",
                "default":"/data/app/mysql"
            },
            {
                "key":"data_dir",
                "name":"数据目录",
                "default":"/data/appData/mysql"
            },
            {
                "key":"data_dir",
                "name":"日志目录",
                "default":"/data/appData/log"
            },
            {
                "key":"username",
                "name":"用户名",
                "default":"root"
            },
            {
                "key":"password",
                "name":"密码",
                "default":"root123"
            }
        ],
        "deploy_mode":{

        },
        "cluster_name":"",
        "instance_name":"mysql-100",
        "dependence":[

        ]
    }
]
```

### 2.5 打包好的应用Demo
查看目录: omp/package_hub/back_end_verified
```shell
filebeat-7.12.0-20220311171107-3e85bed.tar.gz
httpd-2.4.46-20220120145141-b1a6fa6.tar.gz
keepalived-2.1.5-20220120145217-8c6aaf7.tar.gz
postgreSql-13.5.0-20220411212618-6fabab8.tar.gz
redis-5.0.14-20220411212556-6eb6e28.tar.gz
rocketmq-4.8.0-20220410214539-74feff6.tar.gz
```


## 3. 应用服务打包规范

### 3.1. 目录规范

在发布类别为应用服务的产品时,需要将产品名称、所属产品的服务名称、版本号做到全局统一

**目录示例:**

发布产品名称为“omp",其中包含 3个服务为“omp_server","omp_web","omp_component" 的目录结构如下

```shell
$ tree omp
omp
├── omp.svg # 定义产品图标,会在平台中展示,如果不创建则平台会展示缺省图标
├── omp     # 定义产品下服务配置文件目录,将所需服务的配置文件存在该目录
│   ├── omp_server.yaml  # 服务 omp_server 配置文件,文件名需要与服务名称一致
│   ├── omp_web.yaml  # 服务 omp_web 配置文件,文件名需要与服务名称一致
│   └── omp_component.yaml  # 服务 omp_agent 配置文件,文件名需要与服务名称一致
├── omp_server-0.1.0-5d1ac8ce87323fc399506d1335ae5c98.tar.gz  # 服务 omp_server 压缩包,以“-” 为分隔符,第一个为服务名称,需要与服务名称一致,格式为 {service_name}-{service_version}-{others}-{package_md5}.tar.gz
├── omp_web-0.1.0-5d1ac8ce87323fc399506d1335ae5c98.tar.gz  # 服务 omp_web 压缩包
├── omp_component-0.1.0-5d1ac8ce87323fc399506d1335ae5c98.tar.gz  # 服务 omp_agent 压缩包
└── omp.yaml        # 定义产品配置文件,文件名需要与产品名称一致
```

其中服务目录以omp_server为例:

```shell
$ tree omp_server
omp_server    # 服务包解压后目录名称,与服务名一致
├── bin     # 服务控制脚本目录,启动、停止等
│   └── omp_server    # 服务控制脚本,与服务名称一致
├── omp_server.yaml    # 服务配置文件,与产品包中保持一致
└── scripts            # 安装、升级脚本目录
    ├── init.py        # 初始化脚本
    ├── install.py     # 安装脚本
    └── update.py      # 升级脚本
```

### 3.2. 压缩包命名规范

请使用 `{name}-{version}-{others}-{package_md5}.tar.gz`  格式进行打包命名

1. name:   安装包名称,建议字符:  `英文`  `数字`   `_`
2. version: 安装包版本,建议字符:  `英文` `数字` `_`   `.`
3. others:  其他信息,建议字符:  `英文` `数字` `_`   `.`
4. package_md5:  安装包MD5 值

例如: omp-0.1.0-8e955b24fefe7061eb79cfc61a9a02a1.tar.gz

### 3.3. 配置文件yaml说明

发布类别为应用服务的产品时,需分别对 产品配置文件和产品下服务配置文件进行配置

#### 3.3.1. 产品配置文件(yaml)格式说明

```yaml
# 类型定义,发布应用服务时,产品指定类型为 product (类型:string)
kind: product
# 定义产品名称,此名称需要与产品目录名称、产品配置文件名称保持一致,建议字符:英文、数字、_  (类型: string)
name: omp
# 上传后显示的产品版本,建议字符: 数字、字母、_ 、. (类型:string)
version:
# 产品描述信息,建议长度256字符之内,请针对产品书写贴切的描述文字 (类型:string)
description: "运维管理平台(OperationManagementPlatform,以下简称OMP)以管理服务为中心,为服务的安装、管理提供便捷可靠的方式。"
# 组件所属标签,请针对组件功能设置准确标签,平台会针对该标签对组件进行分类,(类型:list[string,string...])
labels:
  - omp
# 定义该产品安装所需依赖产品名称与版本,如不需其他产品依赖,可留空 (类型: list[map,map..])
dependencies:

# 定义该产品下包含的服务信息,请确保列表中的服务包都包含在目录中,并且名称保持一致 (类型: list[map,map...])
service:
    # 包含服务名称,请与服务包名保持一致 (类型: string)
  - name: omp_server
    # 服务版本,请与服务包版本一致 (类型:string)
    version: 0.1.0
  - name: omp_web
    version: 0.1.0
  - name: omp_component
    version: 0.1.0
```

#### 3.3.2. 服务配置文件(yaml)格式说明

```yaml
# 类型定义,发布应用服务时,产品包含的服务指定类型为 service (类型:string)
kind: service
# 服务在平台显示的名称,请与服务目录名称保持一致,建议字符:英文、数字、_ (类型:string)
name: omp_server
# 上传后显示的服务版本,建议字符: 数字、字母、_ 、. (类型:string)
version: 0.1.0
# 服务描述信息,建议长度256字符之内,请针对组件书写贴切的描述文字 (类型:string)
description: "服务描述内容..."
# 指定该服务安装后是否需要启动 (类型:boolean)
auto_launch: true
# 指定服务是否为基础环境组件,如 jdk, 该类组件以基础环境方式安装 (类型:boolean)
base_env: flase
# 定义服务所需端口号,如不启用端口,可留空 (类型:list[map,map...])
ports:
    # 端口描述名称,用户在安装时会以该名称显示表单内容(类型:string)
  - name: 服务端口
    # 端口协议,支持 TCP/UDP
    protocol: TCP
    # 端口英文描述名称,该key会传入到安装脚本中 (类型: string)支持(英文、数字、_)
    key: service_port  # 注:service_port 为保留关键词,表示 为 提供服务的端口
    # 组件的默认端口号,在安装时,会以该值填入表单中(类型: int)
    default: 19001
# 服务监控相关配置,定义该服务在安装后如何监控 ,如果不需要监控可留空 (类型: map)
monitor:
  # 监控进程名称,如“service_a”,平台在发现service_a进程不存在后,会发送告警提醒,不需要监控可留空(类型:string)
  process_name:  ""
  # 监控端口号,请根据 ports 中的变量设置,不需要监控可留空 (类型: {string})
  metric_port: {service_port}
---
# 定义该组件安装所需依赖组件名称与版本,如不需其他组件依赖,可留空 (类型: list[map,map..])
dependencies:
  - name: mysql
    version: 5.7.31
  - name: redis
    version: 5.0.1
  - name: python
    version: 3.8.3
# 该组件所需最小资源需求 (类型:map)
resources:
  # cpu最小需求 ,1000m 表示 1核  (类型:string)
  cpu: 1000m
  # 内存最小需求, 500m 表示 500兆内存 (类型:string)
  memory: 500m
---
# 定义安装组件时所需参数,该参数会传入到 安装脚本中 (类型:list[map,map...])
install:
    # 传入参数中文描述名称,该名称会在用户安装组件时显示到表单中 (类型: string)
  - name: "安装目录"
    # 传入参数key值,会将该key与值 传入到安装脚本中 (类型:string)
    key: base_dir
    # 上面key默认值 (类型: stirng)
    default: "{data_path}/omp_server"  # 注: {data_path} 为主机数据目录占位符,请勿使用其他代替
#  - name: "JVM设置"
#    key: jvm
#    default: "-XX:MaxPermSize=512m -Djava.awt.headless=true"
# 程序控制脚本与服务目录的相对路径 (类型:map)
control:
  # 启动脚本路径,如没有可留空,脚本名称建议与服务名称一致  (类型:string)
  start: "./bin/omp_server start"
  # 停止脚本路径,如没有可留空,脚本名称建议与服务名称一致 (类型:stirng)
  stop: "./bin/omp_server stop"
  # 重启脚本路径,如没有可留空,脚本名称建议与服务名称一致 (类型:stirng)
  restart: "./bin/omp_server restart"
  # 重载脚本路径,如没有可留空 (类型:stirng)
  reload:
  # 安装脚本路径,必填 (类型:stirng)
  install: "./scripts/install.py"
  # 初始化脚本路径,必填 (类型:stirng)
  init:  "./scripts/init.py"
```


================================================
FILE: doc/changelogs.md
================================================
## 更新日志

V0.1.0 (2021.11.30)

- 新增功能:
  【仪表盘】
  - 全局状态概览
  - 当前异常信息展示
  - 各模块状态展示
  【主机管理】
  - 主机纳管(添加、导入、编辑、维护、删除)
  - 主机自动监控、告警
  【应用商店】
  - 组件、应用WEB发布、服务端自动发现
  - 组件、应用部署,自动编排解决依赖
  【服务管理】
  - 服务管理(启动、停止、重启、删除)
  - 服务监控(监控、日志、告警、自愈)
  【应用监控】
  - 实时展示处于异常的主机、服务信息,呼应仪表盘的异常清单
  - 告警历史记录查看,未读提醒,按添加检索
  - 支持监控组件地址自定义,便于对接现有监控平台
  【状态巡检】
  - 支持主机巡检、组件巡检、深度分析,且支持导出
  - 支持定时自动执行巡检任务
  【 系统管理】
  - 用户账户管理
  - 支持全局维护模式,避免人为操作时误报

================================================
FILE: logs/.gitkeep
================================================


================================================
FILE: omp_server/app_store/__init__.py
================================================


================================================
FILE: omp_server/app_store/admin.py
================================================
# from django.contrib import admin

# Register your models here.


================================================
FILE: omp_server/app_store/app_store_filters.py
================================================
"""
应用商店相关过滤器
"""
import django_filters
from django_filters.rest_framework import FilterSet

from db_models.models import (
    Labels, ApplicationHub, ProductHub, UploadPackageHistory,
    MainInstallHistory, Service
)


class LabelFilter(FilterSet):
    """ 标签过滤类 """
    label_type = django_filters.CharFilter(
        help_text="标签类型: 0-组件 1-应用", field_name="label_type", lookup_expr="exact")

    class Meta:
        model = Labels
        fields = ("label_type",)


class ComponentFilter(FilterSet):
    """ 基础组件过滤类 """
    app_name = django_filters.CharFilter(
        help_text="基础组件名称,模糊匹配", field_name="app_name", lookup_expr="icontains")
    type = django_filters.CharFilter(
        help_text="类型名称", field_name="app_labels__label_name", lookup_expr="exact")

    class Meta:
        model = ApplicationHub
        fields = ("app_name", "type")


class ServiceFilter(FilterSet):
    """ 应用服务过滤器类 """
    pro_name = django_filters.CharFilter(
        help_text="应用服务名称,模糊匹配", field_name="pro_name", lookup_expr="icontains")
    type = django_filters.CharFilter(
        help_text="类型名称", field_name="pro_labels__label_name", lookup_expr="exact")

    class Meta:
        model = ProductHub
        fields = ("pro_name", "type")


class UploadPackageHistoryFilter(FilterSet):
    """ 发布-安装包校验结果接口 """
    operation_uuid = django_filters.CharFilter(
        help_text="operation_uuid,查询", field_name="operation_uuid", lookup_expr="exact")

    class Meta:
        model = UploadPackageHistory
        fields = ("operation_uuid",)


class PublishPackageHistoryFilter(FilterSet):
    """ 发布-安装包校验结果接口 """
    operation_uuid = django_filters.CharFilter(
        help_text="operation_uuid,查询", field_name="operation_uuid", lookup_expr="exact")

    class Meta:
        model = UploadPackageHistory
        fields = ("operation_uuid",)


class ComponentEntranceFilter(FilterSet):
    """ 基础组件安装入口过滤类 """
    app_name = django_filters.CharFilter(
        help_text="基础组件名称,精确匹配",
        field_name="app_name", lookup_expr="exact")

    class Meta:
        """ 元数据 """
        model = ApplicationHub
        fields = ("app_name", )


class ProductEntranceFilter(FilterSet):
    """ 基础组件安装入口过滤类 """
    pro_name = django_filters.CharFilter(
        help_text="基础组件名称,精确匹配",
        field_name="pro_name", lookup_expr="exact")

    class Meta:
        """ 元数据 """
        model = ProductHub
        fields = ("pro_name", )


class InstallHistoryFilter(FilterSet):
    """ 基础组件安装入口过滤类 """
    operation_uuid = django_filters.CharFilter(
        help_text="唯一操作的uuid",
        field_name="operation_uuid", lookup_expr="exact")

    class Meta:
        """ 元数据 """
        model = MainInstallHistory
        fields = ("operation_uuid", )


class ServiceInstallHistoryFilter(FilterSet):
    """ 基础组件安装入口过滤类 """
    id = django_filters.NumberFilter(
        help_text="服务id",
        field_name="id", lookup_expr="exact")

    class Meta:
        """ 元数据 """
        model = Service
        fields = ("id", )


================================================
FILE: omp_server/app_store/app_store_serializers.py
================================================
"""
应用商店
"""
import json
import logging
import os
import time
from django.conf import settings

from rest_framework import serializers
from rest_framework.serializers import ModelSerializer
from rest_framework.exceptions import ValidationError
from rest_framework.serializers import Serializer
from utils.common.exceptions import OperateError
from utils.plugin.public_utils import check_is_ip_address, timedelta_strftime
from app_store.tmp_exec_back_task import front_end_verified_init

from db_models.models import (
    ApplicationHub, ProductHub, UploadPackageHistory,
    Service, DetailInstallHistory, MainInstallHistory, Product,
    DeploymentPlan, ExecutionRecord)
from db_models import models

from app_store.install_utils import (
    make_lst_unique, ServiceArgsSerializer,
    SerDependenceParseUtils, ProDependenceParseUtils,
    ValidateExistService, ValidateInstallService,
    CreateInstallPlan
)
from utils.parse_config import HADOOP_ROLE

logger = logging.getLogger("server")


class ComponentListSerializer(ModelSerializer):
    """ 组件列表序列化器 """
    instance_number = serializers.SerializerMethodField()

    class Meta:
        """ 元数据 """
        model = ApplicationHub
        fields = ("app_name", "app_version", "app_logo",
                  "app_description", "instance_number")

    def get_instance_number(self, obj):
        """ 获取组件已安装实例数量 """
        return Service.objects.filter(
            service__app_name=obj.app_name).count()


class ServiceListSerializer(ModelSerializer):
    """ 服务列表序列化器 """
    instance_number = serializers.SerializerMethodField()

    class Meta:
        """ 元数据 """
        model = ProductHub
        fields = ("pro_name", "pro_version", "pro_logo",
                  "pro_description", "instance_number")

    def get_instance_number(self, obj):
        """ 获取组件已安装实例数量 """
        # return Service.objects.filter(
        #     service__product__pro_name=obj.pro_name).count()
        return Product.objects.filter(product=obj).count()


class UploadPackageSerializer(Serializer):
    """上传安装包序列化类"""

    uuid = serializers.CharField(
        help_text="上传安装包uuid",
        required=True,
        error_messages={"required": "必须包含[uuid]字段"}
    )
    operation_user = serializers.CharField(
        help_text="操作用户",
        required=True,
        error_messages={"required": "必须包含[operation_user]字段"}
    )
    file = serializers.FileField(
        help_text="上传的文件",
        required=True,
        error_messages={"required": "必须包含[file]字段"}
    )
    md5 = serializers.CharField(
        help_text="文件包的md5值",
        required=True,
        error_messages={"required": "必须包含[md5]字段"}
    )

    def validate(self, attrs):
        file = attrs.get("file")
        file_name = file.name
        file_size = file.size
        if not file_name.endswith('.tar') and not file_name.endswith('tar.gz'):
            raise ValidationError({
                "file_name": "上传文件名仅支持.tar或.tar.gz"
            })
        # 文件大小超过4G不支持
        if file_size > 4294967296:
            raise ValidationError({
                "file_size": "上传文件大小超过4G"
            })
        return attrs

    def create(self, validated_data):
        uuid = validated_data.get("uuid")
        operation_user = validated_data.get("operation_user")
        request_file = validated_data.get("file")
        md5 = validated_data.get("md5")
        package_name = request_file.name
        if not request_file:
            raise OperateError("上传文件为空")
        destination_dir = os.path.join(
            settings.PROJECT_DIR, 'package_hub/front_end_verified')
        upload_obj = UploadPackageHistory(
            operation_uuid=uuid,
            operation_user=operation_user,
            package_name=package_name,
            package_md5=md5,
            package_path="verified")
        upload_obj.save()
        with open(os.path.join(destination_dir, request_file.name),
                  'wb+') as f:
            for chunk in request_file.chunks():
                try:
                    f.write(chunk)
                except Exception:
                    upload_obj.delete()
                    raise OperateError("文件写入过程失败")

        front_end_verified_init(uuid, operation_user,
                                package_name, upload_obj.id, md5)
        return validated_data


class RemovePackageSerializer(Serializer):
    """ 移除安装包序列化类 """

    uuid = serializers.CharField(
        help_text="上传安装包uuid",
        required=True,
        error_messages={"required": "必须包含[uuid]字段"}
    )

    package_names = serializers.ListField(
        child=serializers.CharField(),
        help_text="安装包名称列表",
        required=True, allow_empty=False,
        error_messages={"required": "必须包含[package_names]字段"}
    )

    def validate(self, attrs):
        """ 校验安装包名称 """
        operation_uuid = attrs.get("uuid")
        package_names = attrs.get("package_names")
        queryset = UploadPackageHistory.objects.filter(
            operation_uuid=operation_uuid,
            package_name__in=package_names,
            package_parent__isnull=True,
            is_deleted=False
        )
        if not queryset.exists() or \
                len(queryset) != len(package_names):
            logger.error(f"remove package error: uuid-{operation_uuid},"
                         f"package_names-{package_names}")
            raise ValidationError({"uuid": "该 uuid 未找到有效的操作记录"})
        attrs["queryset"] = queryset
        return attrs

    def create(self, validated_data):
        """ 上传安装包记录表软删除 """
        queryset = validated_data.pop("queryset", None)
        if queryset is not None:
            queryset.update(is_deleted=True)
        return validated_data


class ApplicationDetailSerializer(ModelSerializer):  # NOQA
    """ 组件详情序列化器 """
    app_instances_info = serializers.SerializerMethodField()
    app_labels = serializers.SerializerMethodField()
    app_package_md5 = serializers.SerializerMethodField()
    app_operation_user = serializers.SerializerMethodField()

    class Meta:
        """ 元数据 """
        model = ApplicationHub
        fields = ("app_name", "app_version", "app_logo", "app_description",
                  "created", "app_dependence", "app_instances_info",
                  "app_labels", "app_package_md5", "app_operation_user")

    def get_app_instances_info(self, obj):  # NOQA
        """ 获取服务安装实例信息 """
        service_objs = Service.objects.filter(service__id=obj.id)
        service_list = []
        for so in service_objs:
            service_dict = {
                "instance_name": so.service_instance_name,
                "host_ip": so.ip,
                "service_port": None if not so.service_port else json.loads(so.service_port),
                "app_version": so.service.app_version,
                "mode": "单实例",  # TODO  后续根据cluster字段是否为空来判断是单实例还是集群模式
                "created": so.created
            }
            service_list.append(service_dict)
        return service_list

    def get_app_labels(self, obj):  # NOQA
        return list(obj.app_labels.all().values_list('label_name', flat=True))

    def get_app_package_md5(self, obj):  # NOQA
        md5 = "-"
        if obj.app_package is not None:
            md5 = obj.app_package.package_md5
        return md5

    def get_app_operation_user(self, obj):  # NOQA
        return obj.app_package.operation_user


class ProductDetailSerializer(ModelSerializer):  # NOQA
    """ 产品详情序列化器 """

    pro_instances_info = serializers.SerializerMethodField()
    pro_labels = serializers.SerializerMethodField()
    pro_package_md5 = serializers.SerializerMethodField()
    pro_operation_user = serializers.SerializerMethodField()
    pro_services = serializers.SerializerMethodField()

    class Meta:
        """ 元数据 """
        model = ProductHub
        fields = ("pro_name", "pro_version", "pro_logo", "pro_description",
                  "created", "pro_dependence", "pro_services",
                  "pro_instances_info",
                  "pro_labels", "pro_package_md5", "pro_operation_user")

    def get_pro_instances_info(self, obj):  # NOQA
        """ 获取服务安装实例信息 """
        service_objs = Service.objects.filter(
            service__product__id=obj.id)
        service_list = []
        for so in service_objs:
            service_dict = {
                "instance_name": so.service_instance_name,
                "version": so.service.product.pro_version,
                "app_name": so.service.app_name,
                "app_version": so.service.app_version,
                "host_ip": so.ip,
                "service_port": None if not so.service_port else json.loads(so.service_port),
                "created": so.created
            }
            service_list.append(service_dict)
        return service_list

    def get_pro_labels(self, obj):  # NOQA
        return list(obj.pro_labels.all().values_list('label_name', flat=True))

    def get_pro_package_md5(self, obj):  # NOQA
        md5 = "-"
        if obj.pro_package is not None:
            md5 = obj.pro_package.package_md5
        return md5

    def get_pro_operation_user(self, obj):  # NOQA
        try:
            return obj.pro_package.operation_user
        except Exception as e:
            logger.error(e)
            logger.error("获取服务包user值失败!")

    def get_pro_services(self, obj):  # NOQA
        pro_services_list = []
        apps = ApplicationHub.objects.filter(product_id=obj.id)
        if not apps:
            if not obj.pro_services:
                return pro_services_list
            pro_services_list.extend(json.loads(obj.pro_services))
            return pro_services_list
        pro_app_name_list = []
        for app in apps:
            uph = UploadPackageHistory.objects.get(id=app.app_package_id)
            if not uph:
                continue
            app_dict = {
                "name": app.app_name,
                "version": app.app_version,
                "created": time.strftime("%Y-%m-%d %H:%M:%S", time.strptime(str(app.created), "%Y-%m-%d %H:%M:%S.%f")),
                "md5": uph.package_md5
            }
            pro_services_list.append(app_dict)
            pro_app_name_list.append(app.app_name)
        for ps in json.loads(obj.pro_services):
            if ps.get("name") in pro_app_name_list:
                continue
            pro_services_list.append(ps)
        return pro_services_list


class UploadPackageHistorySerializer(serializers.ModelSerializer):
    """ 操作记录序列化类 """

    class Meta:
        """ 元数据 """
        model = UploadPackageHistory
        fields = ["package_name", "package_status",
                  "error_msg", "operation_uuid"]


class PublishPackageHistorySerializer(serializers.ModelSerializer):
    """ 操作记录序列化类 """

    class Meta:
        """ 元数据 """
        model = UploadPackageHistory
        fields = ["package_name", "package_status",
                  "error_msg", "operation_uuid"]


class ExecuteLocalPackageScanSerializer(Serializer):
    """ 本地安装包扫描执行序列化类 """
    pass


class ComponentEntranceSerializer(serializers.ModelSerializer):
    """ 组件安装入口数据序列化 """

    app_port = serializers.SerializerMethodField()
    app_dependence = serializers.SerializerMethodField()
    app_install_args = serializers.SerializerMethodField()
    deploy_mode = serializers.SerializerMethodField()
    process_continue = serializers.SerializerMethodField()
    process_message = serializers.SerializerMethodField()

    def get_app_port(self, obj):  # NOQA
        """ 获取服务端口 """
        return ServiceArgsSerializer().get_app_port(obj)

    def get_app_dependence(self, obj):  # NOQA
        """ 解析服务级别的依赖关系 """
        return ServiceArgsSerializer().get_app_dependence(obj)

    def get_app_install_args(self, obj):  # NOQA
        """ 解析服务安装过程中的参数 """
        return ServiceArgsSerializer().get_app_install_args(obj)

    def get_deploy_mode(self, obj):  # NOQA
        """ 解析服务的部署模式 """
        return ServiceArgsSerializer().get_deploy_mode(obj)

    def get_process_continue(self, obj):  # NOQA
        """ 服务能否安装的接口 """
        return ServiceArgsSerializer().get_process_continue(obj)

    def get_process_message(self, obj):  # NOQA
        return ServiceArgsSerializer().get_process_message(obj)

    class Meta:
        """ 元数据 """
        model = ApplicationHub
        fields = [
            "app_name", "app_version", "app_dependence", "app_port",
            "app_install_args", "deploy_mode", "process_continue",
            "process_message"
        ]


class ProductEntranceSerializer(serializers.ModelSerializer):
    """ 产品、应用安装序列化类 """

    pro_services = serializers.SerializerMethodField()
    pro_dependence = serializers.SerializerMethodField()
    dependence_services_info = serializers.SerializerMethodField()

    def get_pro_services(self, obj):  # NOQA
        """ 获取服务列表 """
        if not obj.pro_services:
            return list()
        ser_lst = json.loads(obj.pro_services)
        for item in ser_lst:
            ser_obj = ApplicationHub.objects.filter(
                app_name=item.get("name"),
                app_version=item.get("version")
            ).last()
            if not ser_obj:
                item["process_continue"] = False
                item["process_message"] = f"服务{item.get('name')}未发布"
                continue
            item["app_port"] = ServiceArgsSerializer().get_app_port(ser_obj)
            item["process_continue"] = True
            item["app_install_args"] = \
                ServiceArgsSerializer().get_app_install_args(ser_obj)
            item["deploy_mode"] = \
                ServiceArgsSerializer().get_deploy_mode(ser_obj)
            item["app_dependence"] = \
                ServiceArgsSerializer().get_app_dependence(ser_obj)
        return ser_lst

    def get_pro_dependence(self, obj):  # NOQA
        """ 获取产品依赖关系 """
        _pro = ProDependenceParseUtils(obj.pro_name, obj.pro_version)
        _dep = _pro.run_pro()
        return _dep

    def get_dependence_services_info(self, obj):  # NOQA
        """ 获取服务所依赖的信息 """
        _service_lst = self.get_pro_services(obj=obj)
        if not _service_lst:
            return []
        _all_dependence_ser_info = list()
        for item in _service_lst:
            _ser = SerDependenceParseUtils(
                item.get("name"), item.get("version"))
            _el_lst = _ser.run_ser()
            _all_dependence_ser_info.extend(_el_lst)
        _all_dependence_ser_info = make_lst_unique(
            _all_dependence_ser_info, "name", "version")
        return _all_dependence_ser_info

    class Meta:
        """ 元数据 """
        model = ProductHub
        fields = [
            "pro_name", "pro_version", "pro_dependence",
            "pro_services", "dependence_services_info"
        ]


class ExecuteInstallSerializer(Serializer):
    """
        执行安装时需要解析前端上传的数据的准确性,服务间的关联依赖关系
        目标服务器上实际安装的数据信息等内容
    """

    INSTALL_COMPONENT = 0
    INSTALL_PRODUCT = 1
    INSTALL_TYPE_CHOICES = (
        (INSTALL_COMPONENT, "组件安装"),
        (INSTALL_PRODUCT, "产品安装")
    )
    install_type = serializers.ChoiceField(
        choices=INSTALL_TYPE_CHOICES,
        help_text="选择安装方式: 0-组件; 1-应用",
        required=True, allow_null=False, allow_blank=False,
        error_messages={"required": "必须包含[install_type]字段"}
    )
    use_exist_services = serializers.ListField(
        child=serializers.DictField(),
        help_text="复用已安装的服务列表,eg: [{'name': 'ser1', 'id': 1}]",
        required=True, allow_empty=True,
        error_messages={"required": "必须包含[use_exist_services]字段"}
    )
    install_services = serializers.ListField(
        child=serializers.DictField(),
        help_text="需要安装的服务列表,eg: [{'name': 'ser1', 'version': 1}]",
        required=True, allow_empty=False,
        error_messages={
            "required": "必须包含[install_services]字段",
            "empty": "必须包含将要安装的服务信息"
        }
    )
    is_valid_flag = serializers.BooleanField(
        read_only=True, required=False,
        help_text="数据准确性校验返回标志"
    )
    is_valid_msg = serializers.CharField(
        read_only=True, required=False, max_length=4096,
        help_text="数据准确性校验结果信息"
    )
    operation_uuid = serializers.CharField(
        read_only=True, required=False, max_length=128,
        help_text="成功下发部署计划后返回的uuid"
    )

    def validate_use_exist_services(self, data):  # NOQA
        """
        校验已经存在的服务是否准确
        :param data:
        :return:
        """
        if not data:
            return data
        return ValidateExistService(data=data).run()

    def validate_install_services(self, data):  # NOQA
        """
        校验即将安装的服务及参数
        :param data:
        :return:
        """
        return ValidateInstallService(data=data).run()

    def check_lst_valid(self, lst):  # NOQA
        """
        根据列表、字典格式确定安装参数是否符合要求
        :param lst:
        :return:
        """
        for el in lst:
            if not isinstance(el, dict):
                return False
            if "check_flag" in el and not el["check_flag"]:
                return False
        return True

    def validate(self, attrs):
        """
        安装校验最终要执行的方法,根据安装参数解析结果决定如下操作:
            安装参数解析成功:调用安装参数入库方法
            安装参数解析失败:直接返回相关安装参数
        :param attrs:
        :return:
        """
        valid_lst = list()
        use_exist_services = attrs.get("use_exist_services", [])
        valid_lst.append(self.check_lst_valid(use_exist_services))
        install_services = attrs.get("install_services", [])
        valid_lst.append(self.check_lst_valid(install_services))
        for item in install_services:
            app_install_args = item.get("app_install_args", [])
            valid_lst.append(self.check_lst_valid(app_install_args))
            app_port = item.get("app_port", [])
            valid_lst.append(self.check_lst_valid(app_port))
        logger.info(f"Check install info res: {valid_lst}")
        if len(set(valid_lst)) != 1 or valid_lst[0] is False:
            attrs["is_valid_flag"] = False
            attrs["is_valid_msg"] = "数据校验出错"
            return attrs
        # 数据入库逻辑
        _create_data_obj = CreateInstallPlan(install_data=attrs)
        flag, msg = _create_data_obj.run()
        if not flag:
            attrs["is_valid_flag"] = False
            attrs["is_valid_msg"] = msg
            return attrs
        attrs["is_valid_flag"] = True
        attrs["is_valid_msg"] = ""
        attrs["operation_uuid"] = msg
        return attrs


class InstallHistorySerializer(ModelSerializer):
    """ 安装历史记录序列化类 """
    install_status_msg = serializers.CharField(
        source="get_install_status_display")
    detail_lst = serializers.SerializerMethodField()

    def parse_single_obj(self, obj):  # NOQA
        """
        解析单个服务安装记录信息
        :param obj:
        :type obj: DetailInstallHistory
        :return:
        """
        _status = obj.install_step_status
        # 拼接日志
        _log = ""
        if obj.send_flag != 0 and obj.send_msg:
            _log += obj.send_msg
        if obj.unzip_flag != 0 and obj.unzip_msg:
            _log += obj.unzip_msg
        if obj.install_flag != 0 and obj.install_msg:
            _log += obj.install_msg
        if obj.init_flag != 0 and obj.init_msg:
            _log += obj.init_msg
        if obj.start_flag != 0 and obj.start_msg:
            _log += obj.start_msg
        return {
            "ip": obj.service.ip,
            "status": _status,
            "log": _log,
            "service_name": obj.service.service.app_name,
            "service_instance_name": obj.service.service_instance_name
        }

    def get_detail_lst(self, obj):  # NOQA
        """
        获取安装细节表
        :param obj:
        :return:
        """
        lst = DetailInstallHistory.objects.filter(
            main_install_history=obj
        )
        return [self.parse_single_obj(el) for el in lst]

    class Meta:
        """ 元数据 """
        model = MainInstallHistory
        fields = (
            "operation_uuid", "install_status", "install_status_msg",
            "install_args", "install_log", "detail_lst"
        )


class ServiceInstallHistorySerializer(ModelSerializer):
    """ 安装历史记录序列化类 """
    install_step_status = serializers.SerializerMethodField()
    log = serializers.SerializerMethodField()

    def get_install_step_status(self, obj):
        """
        获取服务安装状态
        :param obj:
        :return:
        """
        detail_obj = DetailInstallHistory.objects.filter(service=obj).last()
        return detail_obj.install_step_status

    def get_log(self, obj):
        """
        获取服务日志信息
        :param obj:
        :return:
        """
        detail_obj = DetailInstallHistory.objects.filter(service=obj).last()
        _log = ""
        if detail_obj.send_flag != 0 and detail_obj.send_msg:
            _log += detail_obj.send_msg
        if detail_obj.unzip_flag != 0 and detail_obj.unzip_msg:
            _log += detail_obj.unzip_msg
        if detail_obj.install_flag != 0 and detail_obj.install_msg:
            _log += detail_obj.install_msg
        if detail_obj.init_flag != 0 and detail_obj.init_msg:
            _log += detail_obj.init_msg
        if detail_obj.start_flag != 0 and detail_obj.start_msg:
            _log += detail_obj.start_msg
        return _log

    class Meta:
        """ 元数据 """
        model = Service
        fields = (
            "install_step_status", "log"
        )


class DeploymentPlanValidateSerializer(Serializer):
    """ 部署计划服务信息验证序列化类 """

    instance_name_ls = serializers.ListField(
        child=serializers.CharField(),
        help_text="主机实例名列表",
        required=True, allow_empty=False,
        error_messages={"required": "必须包含[instance_name_ls]字段"}
    )

    service_data_ls = serializers.ListField(
        child=serializers.DictField(),
        help_text="服务数据列表",
        required=True, allow_empty=False,
        error_messages={"required": "必须包含[host_list]字段"}
    )

    def validate(self, attrs):
        """ 校验主机数据列表 """
        instance_name_ls = attrs.get("instance_name_ls")
        service_data_ls = attrs.get("service_data_ls")
        result_dict = {
            "correct": [],
            "error": []
        }
        logger.info("deployment plan validate start")

        # 查询所有 application 信息
        service_name_ls = list(
            map(lambda x: x.get("service_name"), service_data_ls))
        _queryset = ApplicationHub.objects.filter(
            app_name__in=service_name_ls, is_release=True)
        # 所有 application 默认取最新
        new_app_id_list = []
        for app in _queryset:
            new_version = _queryset.filter(
                app_name=app.app_name
            ).order_by("-created").first().app_version
            if new_version == app.app_version:
                new_app_id_list.append(app.id)
        app_queryset = _queryset.filter(
            id__in=new_app_id_list, is_release=True
        ).select_related("product")

        # 获取 application 对应的 product 信息
        app_now = app_queryset.exclude(product__isnull=True)
        pro_id_list = app_now.values_list("product_id", flat=True).distinct()
        # 验证 product 的依赖项均已包含
        pro_queryset = ProductHub.objects.filter(id__in=pro_id_list)
        app_target_all = ApplicationHub.objects.filter(
            product_id__in=pro_id_list)
        # 考虑到同产品下会有同名服务情况,做去重处理,按照时间版本号取最新
        app_target = []
        for pro in pro_queryset:
            for ser in json.loads(pro.pro_services):
                app_target.append(
                    app_target_all.filter(
                        app_name=ser["name"], app_version=ser["version"]
                    ).last()
                )
            # 无依赖项则跳过
            if not pro.pro_dependence:
                continue
            dependence_list = json.loads(pro.pro_dependence)
            # 校验依赖项的指定版本是否存在
            for dependence in dependence_list:
                name = dependence.get("name")
                # version = dependence.get("version")
                pro_obj = pro_queryset.filter(
                    pro_name=name).order_by("-created").first()
                # if not pro_obj or not pro_obj.pro_version.startswith(version):
                if not pro_obj:
                    result_dict["error"].append({
                        "row": -2,
                        "instance_name": "待补充",
                        "service_name": "待补充",
                        "validate_error": f"产品 {pro.pro_name}-{pro.pro_version} "
                                          f"缺失依赖产品 {name}"
                    })

        # 验证所有 product 下的 application 都已经包含
        app_target_all = ApplicationHub.objects.filter(
            product_id__in=pro_id_list)

        # 所有 affinity 为 tengine 字段 (Web 服务),不参与比较
        now_set = set(filter(
            lambda x: x.extend_fields.get("affinity") != "tengine", app_now))
        target_set = set(filter(
            lambda x: x.extend_fields.get("affinity") != "tengine", app_target))
        diff_set = target_set - now_set

        # 存在遗漏的 application
        if diff_set:
            for app in diff_set:
                result_dict["error"].append({
                    "row": -1,
                    "instance_name": "待补充",
                    "service_name": f"{app.app_name}",
                    "validate_error": f"产品 {app.product.pro_name} "
                                      f"缺失依赖服务 {app.app_name}"
                })

        # 验证所有 application 的依赖项均已包含
        base_env_queryset = ApplicationHub.objects.filter(is_base_env=True)
        for app in app_queryset:
            if not app.app_dependence:
                continue
            dependence_list = json.loads(app.app_dependence)
            # 校验依赖项的指定版本是否存在
            for dependence in dependence_list:
                name = dependence.get("name")
                # version = dependence.get("version")
                app_obj = app_queryset.filter(
                    app_name=name).order_by("-created").first()
                # if not app_obj or not app_obj.app_version.startswith(version):
                if not app_obj:
                    # 如果为 base_env 则跳过
                    # if base_env_queryset.filter(
                    #         app_name=name, app_version=version
                    # ).exists():
                    if base_env_queryset.filter(app_name=name).exists():
                        continue
                    result_dict["error"].append({
                        "row": -2,
                        "instance_name": "待补充",
                        "service_name": f"{name}",
                        "validate_error": f"服务 {app.app_name}-{app.app_version} "
                                          f"缺失依赖服务 {name}"
                    })

        # hadoop 实例列表、角色集合
        hadoop_instance_ls = []
        hadoop_role_set = set()

        for service_data in service_data_ls:
            # 校验主机数据是否已经存在
            if service_data.get("instance_name") not in instance_name_ls:
                service_data["validate_error"] = "主机不在表格中"
                result_dict["error"].append(service_data)
                continue
            # 校验服务是否存在
            app_name = service_data.get("service_name", "unKnow")
            if not app_queryset.filter(
                    app_name=app_name
            ).order_by("-created").exists():
                service_data["validate_error"] = f"{app_name}服务不在应用商店中"
                result_dict["error"].append(service_data)
                continue
            # 如果含 vip 字段,校验是否为 IP 格式
            if service_data.get("vip"):
                is_valid, _ = check_is_ip_address(
                    service_data.get("vip"))
                if not is_valid:
                    service_data["validate_error"] = "虚拟IP不合法"
                    result_dict["error"].append(service_data)
                    continue
            # 如果含 role 字段,校验是否含中文逗号
            if service_data.get("role") and \
                    "," in service_data.get("role"):
                service_data["validate_error"] = "角色请用英文逗号分隔"
                result_dict["error"].append(service_data)
                continue
            # 当服务名为 hadoop 时,记录 hadoop 实例列表、角色集合
            if app_name == "hadoop":
                hadoop_instance_ls.append(service_data)
                if service_data.get("role"):
                    hadoop_role_set = hadoop_role_set | set(
                        service_data.get("role").split(","))
                continue
            result_dict["correct"].append(service_data)

        # 如果存在 hadoop 实例,则校验角色
        if hadoop_instance_ls:
            key_name = "single"
            if len(hadoop_instance_ls) > 1:
                key_name = "cluster"
            diff = set(HADOOP_ROLE.get(key_name)) - hadoop_role_set
            if diff:
                for hadoop_instance in hadoop_instance_ls:
                    hadoop_instance["validate_error"] = f"缺少角色{','.join(diff)}"
                    result_dict["error"].append(hadoop_instance)
            else:
                for hadoop_instance in hadoop_instance_ls:
                    result_dict["correct"].append(hadoop_instance)

        # 按照 row 行号对列表进行排序
        for v in result_dict.values():
            if len(v) > 0:
                v.sort(key=lambda x: x.get("row", 999))
        attrs["result_dict"] = result_dict
        logger.info("deployment plan validate end")
        return attrs


class DeploymentImportSerializer(Serializer):
    """ 部署计划导入序列化类 """

    instance_info_ls = serializers.ListField(
        child=serializers.DictField(),
        help_text="主机信息列表",
        required=True, allow_empty=False,
        error_messages={"required": "必须包含[instance_info_ls]字段"}
    )

    service_data_ls = serializers.ListField(
        child=serializers.DictField(),
        help_text="服务数据列表",
        required=True, allow_empty=False,
        error_messages={"required": "必须包含[host_list]字段"}
    )

    operation_uuid = serializers.CharField(
        max_length=64,
        help_text="唯一操作id",
        required=False
    )


class DeploymentPlanListSerializer(ModelSerializer):
    """ 部署计划列表序列化类 """

    class Meta:
        """ 元数据 """
        model = DeploymentPlan
        fields = "__all__"


class ExecutionRecordSerializer(ModelSerializer):
    state_display = serializers.CharField(source="get_state_display")
    can_rollback = serializers.SerializerMethodField()
    duration = serializers.SerializerMethodField()

    def get_can_rollback(self, obj):
        if obj.module != "UpgradeHistory":
            return False
        module_obj = getattr(models, obj.module).objects.get(
            id=int(obj.module_id)
        )
        return module_obj.can_roll_back

    def get_duration(self, obj):
        if not obj.end_time:
            return "-"
        return timedelta_strftime(obj.end_time - obj.created)

    class Meta:
        model = ExecutionRecord
        fields = ("id", "operator", "count", "state", "state_display",
                  "can_rollback", "duration", "created", "end_time",
                  "module", "module_id")


class ProductCompositionSerializer(ModelSerializer):
    pro_ser_others = serializers.SerializerMethodField()
    pro_services = serializers.CharField(
        # child=serializers.DictField(),
        help_text="产品包含服务列表",
        required=True,
        error_messages={"required": "必须包含[pro_services]字段"}
    )
    pro_name = serializers.CharField(help_text="产品名称", required=True,
                                     error_messages={"required": "请填写产品名称"})
    pro_version = serializers.CharField(help_text="产品版本", required=True,
                                        error_messages={"required": "请填写产品版本"})

    def get_pro_ser_others(self, obj, **kwargs):
        res_list = []
        all_apps_set, all_true_apps_set = set(), set()
        if obj.applicationhub_set.exists():
            all_apps = obj.applicationhub_set.values_list("app_name", "app_version")
            for app in all_apps:
                all_apps_set.add(",".join(app))
        pro_ser = kwargs.get('pro_ser')
        pro_services = pro_ser if pro_ser else json.loads(obj.pro_services)
        for t_app in pro_services:
            all_true_apps_set.add(f"{t_app['name']},{t_app['version']}")
        # 一部分用作校验用
        if pro_ser:
            return all_true_apps_set - all_apps_set

        for r_app in all_apps_set - all_true_apps_set:
            r_app_ls = r_app.split(",")
            res_list.append(
                {
                    "name": r_app_ls[0],
                    "version": r_app_ls[1],
                }
            )
        return res_list

    def validate_pro_services(self, pro_services):
        pro_services = json.loads(pro_services)
        if not isinstance(pro_services, list):
            raise ValidationError({
                "pro_services": "pro_services必须是list"
            })
        pro_ser_len = len(pro_services)
        ser_name = {}
        for app in pro_services:
            ser_name[app.get('name', "")] = app.get('version', '')
        if len(ser_name) != pro_ser_len:
            raise ValidationError({
                "pro_services": "产品内服务名称需保证唯一或字段传递异常"
            })
        return pro_services

    def validate(self, attrs):
        pro_name = attrs.get("pro_name")
        pro_version = attrs.get("pro_version")
        pro_obj = ProductHub.objects.filter(pro_name=pro_name, pro_version=pro_version).first()
        if not pro_obj:
            raise ValidationError({
                "pro_services": "请填写正确的产品名称和版本"
            })

        diff_ser = self.get_pro_ser_others(pro_obj, pro_ser=attrs.get("pro_services"))
        if diff_ser:
            raise ValidationError({
                "pro_services": f"存在不归属于当前产品的服务{diff_ser}"
            })
        return attrs

    class Meta:
        model = ProductHub
        fields = ("pro_name", "pro_version", "pro_services", "pro_ser_others")


class DeleteComponentSerializer(ModelSerializer):
    """
    基础组件序列化
    """
    name = serializers.SerializerMethodField()
    versions = serializers.SerializerMethodField()

    class Meta:
        """ 元数据 """
        model = ApplicationHub
        fields = ("name", "versions")

    def get_name(self, obj):
        return obj.app_name

    def get_versions(self, obj):
        return [obj.app_version]


class DeleteProDuctSerializer(ModelSerializer):
    """
    产品序列化
    """
    name = serializers.SerializerMethodField()
    versions = serializers.SerializerMethodField()

    class Meta:
        """ 元数据 """
        model = ProductHub
        fields = ("name", "versions")

    def get_name(self, obj):
        return f"{obj.pro_name}|{obj.pro_version}"

    def get_versions(self, obj):
        app_ls = []
        app_values = ApplicationHub.objects.filter(
            product=obj).values_list("app_name", "app_version")
        for app in app_values:
            app_ls.append(f"{app[0]}|{app[1]}")
        return app_ls


================================================
FILE: omp_server/app_store/apps.py
================================================
from django.apps import AppConfig


class AppStoreConfig(AppConfig):
    name = 'app_store'


================================================
FILE: omp_server/app_store/cmd_install_utils.py
================================================
# -*- coding: utf-8 -*-
# Project: cmd_install_utils
# Author: jon.liu@yunzhihui.com
# Create time: 2022-01-07 15:10
# IDE: PyCharm
# Version: 1.0
# Introduction:

import os

import xlrd


class ReadDeploymentExcel(object):
    """ 读取部署表格使用类 """

    def __init__(self, excel_path):
        """
        :param excel_path: 表格文件绝对路径
        """
        self.excel_path = excel_path

    @staticmethod
    def _read(start_row=1, keys=None, table=None):
        """
        真正读取表格数据,返回tuple (True, list) or (False, str)
        :param start_row:
        :param keys:
        :param table:
        :return:
        """
        # 获取总行数 总列数
        row_num = table.nrows
        col_num = table.ncols

        _res = []
        # 这是第一行数据,作为字典的key值
        key = table.row_values(0)

        if row_num <= start_row:
            return False, "所需要数据行数下无数据"
        # 读取行数的控制逻辑
        for i in range(row_num - 1):
            # 行数据字典
            row_data = {}
            # 如果当前获取到的数据的行数小于想要的行数时,则跳过,不留存
            if i < start_row:
                continue
            values = table.row_values(i + 1)
            # 循环每列获取数据
            for x in range(col_num):
                _key = None
                if key[x] not in keys:
                    continue
                _key = keys[key[x]]
                # 提取真正的值
                value = int(values[x]) if isinstance(values[x], float) \
                    else values[x]
                row_data[_key] = str(value).strip()
                row_data["row"] = i + 1
            if not row_data:
                continue
            # 把字典加到列表中
            _res.append(row_data)
        return _res

    def read_host_info(self, table):
        """
        获取节点信息
        :param table: 节点信息页对象
        :return:
        """
        keys_map = {
            "实例名[必填]": "instance_name",
            "IP[必填]": "ip",
            "端口[必填]": "port",
            "用户名[必填]": "username",
            "密码[必填]": "password",
            "数据分区[必填]": "data_folder",
            "操作系统[必填]": "operate_system",
            "是否执行初始化": "init_host",
            "运行用户": "run_user",
            "时间同步服务器": "ntpd_server"
        }
        return self._read(start_row=4, keys=keys_map, table=table)

    def read_service_info(self, table):
        """
        获取服务分布表格信息
        :param table: 服务分布页对象
        :return:
        """
        keys_map = {
            "主机实例名[必填]": "instance_name",
            "服务名[必填]": "service_name",
            "运行内存": "memory",
            "虚拟IP": "vip",
            "角色": "role",
            "模式": "mode"
        }
        return self._read(start_row=3, keys=keys_map, table=table)

    def read_excel(self):
        """
        读取表格数据
        :return:
        """
        if not os.path.exists(self.excel_path) or \
                not os.path.isfile(self.excel_path):
            return False, f"无法找到此文件: {self.excel_path}"
        # 打开excel表,填写路径
        book = xlrd.open_workbook(self.excel_path)
        # 找到sheet页
        host_table = book.sheet_by_name("节点信息")
        host_info = self.read_host_info(table=host_table)
        for item in host_info:
            if item["username"] == "root":
                item["init_host"] = True
            else:
                item["init_host"] = False
            if "ntpd_server" in item and item["ntpd_server"] != "":
                item["use_ntpd"] = True
            else:
                item["use_ntpd"] = False
                item.pop("ntpd_server", "")
        service_table = book.sheet_by_name("服务分布")
        service_info = self.read_service_info(table=service_table)
        return True, {
            "host": host_info,
            "service": {
                "instance_name_ls": [el["instance_name"] for el in host_info],
                "service_data_ls": service_info
            }
        }


================================================
FILE: omp_server/app_store/deploy_mode_utils/__init__.py
================================================
# -*- coding: utf-8 -*-
# Project: __init__.py
# Author: jon.liu@yunzhihui.com
# Create time: 2021-11-16 16:44
# IDE: PyCharm
# Version: 1.0
# Introduction:

"""
服务部署模式
"""

from app_store.deploy_mode_utils.mysql import MysqlUtils
# from app_store.deploy_mode_utils.normal import NormalUtils
from app_store.deploy_mode_utils.odd_num import OddNumUtils
# from app_store.deploy_mode_utils.even_num import EvenNumUtils
from app_store.deploy_mode_utils.tengine import TengineUtils
from app_store.deploy_mode_utils.rocketmq import RocketmqUtils


SERVICE_MAP = {
    "mysql": MysqlUtils,
    "zookeeper": OddNumUtils,
    "kafka": OddNumUtils,
    "nacos": OddNumUtils,
    "tengine": TengineUtils,
    "rocketmq": RocketmqUtils
}


================================================
FILE: omp_server/app_store/deploy_mode_utils/base.py
================================================
# -*- coding: utf-8 -*-
# Project: base
# Author: jon.liu@yunzhihui.com
# Create time: 2021-11-16 17:10
# IDE: PyCharm
# Version: 1.0
# Introduction:


class BaseUtils(object):
    """ 部署模式基础类 """

    def __init__(self, host_num, high_availability):
        """
        :param host_num: 主机数量
        :type host_num: int
        :param high_availability: 是否使用高可用
        :type high_availability: bool
        """
        self.host_num = host_num
        self.high_availability = high_availability

    def get(self):
        """
        获取部署模式
        :return:
        """
        raise NotImplementedError(f"{self}必须实现get方法!")

    def check(self, mode):
        """
        校验部署模式
        :param mode: 部署模式
        :return:
        """
        raise NotImplementedError(f"{self}必须实现check方法!")


================================================
FILE: omp_server/app_store/deploy_mode_utils/even_num.py
================================================
# -*- coding: utf-8 -*-
# Project: even_num
# Author: jon.liu@yunzhihui.com
# Create time: 2021-11-23 15:55
# IDE: PyCharm
# Version: 1.0
# Introduction:

"""
偶数服务集群部署模式
偶数服务集群最小为4
"""

from app_store.deploy_mode_utils.base import BaseUtils


class EvenNumUtils(BaseUtils):
    """ 偶数集群控制 """

    def get(self):
        """
        当服务集群为偶数个时,返回部署模式
        :return:
        """
        if self.host_num < 4:
            return {
                "default": 1,
                "step": 0
            }
        return {
            "default": 4,
            "step": 2
        }

    def check(self, mode):
        """
        检查服务集群部署规则 TODO 待完善
        :param mode:
        :type mode: int
        :return:
        """
        if mode > self.host_num:
            return False
        if self.host_num < 4 and mode > 1:
            return False
        return True


================================================
FILE: omp_server/app_store/deploy_mode_utils/mysql.py
================================================
# -*- coding: utf-8 -*-
# Project: mysql
# Author: jon.liu@yunzhihui.com
# Create time: 2021-11-16 16:45
# IDE: PyCharm
# Version: 1.0
# Introduction:

"""
mysql部署模式工具
"""

from app_store.deploy_mode_utils.base import BaseUtils


class MysqlUtils(BaseUtils):
    """ MySQL的部署模式 """

    def get(self):
        """
        获取mysql的部署模式
        :return:
        """
        if self.host_num == 1:
            return [
                {
                    "key": "single",
                    "name": "单实例"
                }
            ]
        elif self.high_availability and self.host_num >= 2:
            return [
                {
                    "key": "master-slave",
                    "name": "主从"
                },
                {
                    "key": "master-master",
                    "name": "主主(vip)"
                },
                {
                    "key": "single",
                    "name": "单实例"
                }
            ]
        return [
            {
                "key": "single",
                "name": "单实例"
            },
            {
                "key": "master-slave",
                "name": "主从"
            },
            {
                "key": "master-master",
                "name": "主主(vip)"
            }
        ]

    def check(self, mode):
        """
        检查部署模式是否符合要求
        :param mode: 部署模式
        :type mode: str
        :return:
        """
        if self.host_num == 1:
            if mode == "single":
                return True
            return False
        if self.host_num >= 2 and \
                mode in ("single", "master-slave", "master-master"):
            return True
        return False


================================================
FILE: omp_server/app_store/deploy_mode_utils/normal.py
================================================
# -*- coding: utf-8 -*-
# Project: normal
# Author: jon.liu@yunzhihui.com
# Create time: 2021-11-23 16:06
# IDE: PyCharm
# Version: 1.0
# Introduction:

"""
普通服务的集群模式
起始为1 步长为1
"""

from app_store.deploy_mode_utils.base import BaseUtils


class NormalUtils(BaseUtils):
    """ 普通集群控制 """

    def get(self):
        """
        普通服务,返回部署模式
        :return:
        """
        if self.host_num == 1:
            return {
                "default": 1,
                "step": 0
            }
        return {
            "default": 1,
            "step": 1
        }

    def check(self, mode):
        """
        检查服务集群部署规则 TODO 待完善
        :param mode:
        :type mode: int
        :return:
        """
        if mode > self.host_num:
            return False
        return True


================================================
FILE: omp_server/app_store/deploy_mode_utils/odd_num.py
================================================
# -*- coding: utf-8 -*-
# Project: odd_num
# Author: jon.liu@yunzhihui.com
# Create time: 2021-11-23 15:55
# IDE: PyCharm
# Version: 1.0
# Introduction:

"""
奇数服务集群部署模式
奇数服务集群最小为3
"""

from app_store.deploy_mode_utils.base import BaseUtils


class OddNumUtils(BaseUtils):
    """ 奇数集群控制 """

    def get(self):
        """
        当服务集群为奇数个时,返回部署模式
        :return:
        """
        if self.host_num < 3:
            return {
                "default": 1,
                "step": 0
            }
        if not self.high_availability:
            return {
                "default": 1,
                "step": 2
            }
        return {
            "default": 3,
            "step": 2
        }

    def check(self, mode):
        """
        检查服务集群部署规则 TODO 待完善
        :param mode:
        :type mode: int
        :return:
        """
        if mode > self.host_num:
            return False
        if self.host_num < 3 and mode > 1:
            return False
        return True


================================================
FILE: omp_server/app_store/deploy_mode_utils/rocketmq.py
================================================
# -*- coding: utf-8 -*-
# Project: mysql
# Author: jon.liu@yunzhihui.com
# Create time: 2021-11-16 16:45
# IDE: PyCharm
# Version: 1.0
# Introduction:

"""
rocketmq部署模式工具
"""

from app_store.deploy_mode_utils.base import BaseUtils


class RocketmqUtils(BaseUtils):
    """ Rocket的部署模式 """

    def get(self):
        """
        获取mysql的部署模式
        :return:
        """
        if self.host_num == 1:
            return {
                "default": 1,
                "step": 0
            }
        if self.high_availability:
            if self.host_num >= 2:
                return {
                    "default": 2,
                    "step": 2
                }
            return {
                "default": 1,
                "step": 0
            }
        return {
            "default": 1,
            "step": 1
        }

    def check(self, mode):
        """
        检查部署模式是否符合要求
        :param mode: 部署模式
        :type mode: str
        :return:
        """
        return True


================================================
FILE: omp_server/app_store/deploy_mode_utils/tengine.py
================================================
# -*- coding: utf-8 -*-
# Project: tengine
# Author: jon.liu@yunzhihui.com
# Create time: 2021-11-23 16:26
# IDE: PyCharm
# Version: 1.0
# Introduction:

"""
tengine部署模式工具
"""

from app_store.deploy_mode_utils.base import BaseUtils


class TengineUtils(BaseUtils):
    """ tengine的部署模式 """

    def get(self):
        """
        获取tengine的部署模式
        :return:
        """
        # return {
        #     "default": 1,
        #     "step": 1
        # }
        return [
            {
                "key": "single",
                "name": "单实例"
            },
            {
                "key": "master-master",
                "name": "主主(vip)"
            }
        ]

    def check(self, mode):
        """
        检查部署模式是否符合要求
        :param mode: 部署模式
        :type mode: int
        :return:
        """
        # if mode != 1:
        #     return False
        return True


================================================
FILE: omp_server/app_store/deploy_role_utils/__init__.py
================================================
# -*- coding: utf-8 -*-
# Project: __init__.py
# Author: jerry.zhang@yunzhihui.com
# Create time: 2021-12-15 15:46
# IDE: PyCharm
# Version: 1.0
# Introduction:

from app_store.deploy_role_utils.hadoop import Hadoop
from app_store.deploy_role_utils.redis import Redis
from app_store.deploy_role_utils.mysql import Mysql

DEPLOY_ROLE_UTILS = {
    "hadoop": Hadoop,
    "redis": Redis,
    "mysql": Mysql
}


================================================
FILE: omp_server/app_store/deploy_role_utils/hadoop.py
================================================
# -*- coding: utf-8 -*-
# Project: __init__.py
# Author: jerry.zhang@yunzhihui.com
# Create time: 2021-12-16 10:10
# IDE: PyCharm
# Version: 1.0
# Introduction:

import logging

logger = logging.getLogger("server")


class Hadoop(object):
    @staticmethod
    def update_service(service_list):
        """
        分配hadoop服务角色
        :param service_list: 服务数据列表
        :return:
        """
        need_distribution = [
            "namenode,zkfc", "resourcemanager", "namenode,zkfc", "resourcemanager"]
        base_role = "datanode,nodemanager,journalnode"
        # worker_role = "datanode,nodemanager" 后期优化分配
        if len(service_list) == 1:
            service_list[0]['roles'] = "namenode,secondarynamenode," \
                                       "datanode,resourcemanager,nodemanager"
            return service_list
        for index, i in enumerate(service_list):
            if i.get('roles'):
                continue
            if index == len(service_list) - 1 and len(need_distribution) > 1:
                i['roles'] = "{0},{1}".format(
                    base_role, ",".join(need_distribution))
            elif index == 0 and len(service_list) == 2:
                i['roles'] = "{0},{1}".format(
                    base_role, ",".join(need_distribution[:2]))
                need_distribution = need_distribution[2:]
            elif len(service_list) >= 5 and need_distribution[0] == "namenode,zkfc":
                role = need_distribution.pop(0)
                i['roles'] = f"journalnode,{role}"
            else:
                role = need_distribution.pop(0)
                i['roles'] = f"{base_role},{role}"
        return service_list


================================================
FILE: omp_server/app_store/deploy_role_utils/mysql.py
================================================
# -*- coding: utf-8 -*-
# Project: mysql
# Author: jon.liu@yunzhihui.com
# Create time: 2021-12-21 20:22
# IDE: PyCharm
# Version: 1.0
# Introduction:


import logging

logger = logging.getLogger("server")


class Mysql(object):
    @staticmethod
    def update_service(service_list):
        """
        分配mysql的角色
        :param service_list: 服务数据列表
        :return:
        """
        mysql_index_lst = list()
        mysql_vip_flag = False
        for index, item in enumerate(service_list):
            logger.info(f"{mysql_vip_flag}; {item}")
            if item.get("name") == "mysql":
                mysql_index_lst.append(index)
            if item.get("roles") == "mysql":
                mysql_vip_flag = True
        if len(mysql_index_lst) == 1:
            service_list[mysql_index_lst[0]]["roles"] = "single"
        elif len(mysql_index_lst) == 2:
            if not mysql_vip_flag:
                service_list[mysql_index_lst[0]]["roles"] = "master"
                service_list[mysql_index_lst[1]]["roles"] = "slave"
            else:
                service_list[mysql_index_lst[0]]["roles"] = "master"
                service_list[mysql_index_lst[1]]["roles"] = "master"
        return service_list


================================================
FILE: omp_server/app_store/deploy_role_utils/redis.py
================================================
# -*- coding: utf-8 -*-
# Project: __init__.py
# Author: jerry.zhang@yunzhihui.com
# Create time: 2021-12-16 10:10
# IDE: PyCharm
# Version: 1.0
# Introduction:

import logging

logger = logging.getLogger("server")


class Redis(object):
    @staticmethod
    def update_service(service_list):
        """
        分配redis服务角色
        :param service_list: 服务数据列表
        :return:
        """
        if len(service_list) == 1:
            service_list[0]['roles'] = "master"
        for index, i in enumerate(service_list):
            if i.get('roles'):
                continue
            if index == 0:
                i['roles'] = "master"
            else:
                i['roles'] = "slave"
        return service_list


================================================
FILE: omp_server/app_store/high_availability_utils/__init__.py
================================================
# -*- coding: utf-8 -*-
# Project: __init__.py
# Author: jerry.zhang@yunzhihui.com
# Create time: 2021-12-15 15:46
# IDE: PyCharm
# Version: 1.0
# Introduction:

from app_store.high_availability_utils.hadoop import Hadoop

HIGH_AVAILABILITY_UTILS = {
    "hadoop": Hadoop
}


================================================
FILE: omp_server/app_store/high_availability_utils/hadoop.py
================================================
import logging
import os
import json
from utils.common.exceptions import GeneralError
from db_models.models import (
    Service, DetailInstallHistory,
    Host, ServiceHistory,
    ClusterInfo
)
from django.db.models import F
from django.db import transaction
from concurrent.futures import (
    ThreadPoolExecutor, as_completed
)
from utils.plugin.salt_client import SaltClient

THREAD_POOL_MAX_WORKERS = 20
logger = logging.getLogger("server")


class Hadoop(object):
    ACTION_LS = ("send", "unzip", "install")
    hadoop_init = [
        ("init", "zkfc"), ("start", "journalnode"),
        ("format", "namenode"), ("sync", "namenode"),
        ("start", "zkfc"), ("start", "datanode"),
        ("start", "resourcemanager"), ("start", "nodemanager")
    ]

    def __init__(self, install_exec_obj, detail_list_obj):
        """
        解析数据
        :param install_exec_obj InstallServiceExecutor对象实例
        :parm detail_list_obj detail的orm对象列表
        :return:
        """
        self.install_obj = install_exec_obj
        self.detail_list = detail_list_obj
        self.timeout = 300
        self.error = False
        self.target_set = set()
        self.count = 0
        self.detail_dict = {}  # 中间结果,任意一个hadoop_init失败所有的detail对象全部失败
        self.port = {}
        self.base_dir = {}

    def check_result(self, future_list):
        for future in as_completed(future_list):
            is_success, message = future.result()
            if not is_success:
                self.install_obj.is_error = True
                self.error = True
                break
        self.count += 1

    def init_hadoop(self, detail_obj, target_ip, service_controllers_dict, action):
        try:
            # 获取服务初始化脚本绝对路径
            salt_client = SaltClient()
            init_script_path = service_controllers_dict.get("init", "")
            # 获取 json 文件路径
            target_host = Host.objects.filter(ip=target_ip).first()
            assert target_host is not None
            json_path = os.path.join(
                target_host.data_folder, "omp_packages",
                f"{detail_obj.main_install_history.operation_uuid}.json")

            cmd_str = f"python {init_script_path} --local_ip {target_ip} " \
                      f"--data_json {json_path} --action_type {action[0]} --action_object {action[1]}"
            # 执行初始化
            is_success, message = salt_client.cmd(
                target=target_ip,
                command=cmd_str,
                timeout=self.timeout)
            if not is_success:
                raise GeneralError(message)
            # 执行成功且 message 有值,则补充至服务日志中
            detail_obj.install_msg += \
                f"{self.install_obj.now_time()} 初始化脚本执行成功,脚本输出如下:\n" \
                f"{message}\n"
            detail_obj.save()
            return True, "success"
        except Exception as err:
            for obj, name in self.detail_dict.items():
                logger.error(f"Init Failed -> [{name}]: {err}")
                obj.init_flag = 3
                obj.init_msg += f"{self.install_obj.now_time()} {name} " \
                                f"初始化服务失败: {err}\n"
                # 更新安装流程状态为 '失败',服务状态为 '安装失败'
                obj.install_step_status = \
                    DetailInstallHistory.INSTALL_STATUS_FAILED
                obj.save()
                obj.service.service_status = \
                    Service.SERVICE_STATUS_INSTALL_FAILED
                obj.service.save()
                # 创建历史记录
                self.install_obj.create_history(obj, is_success=False)
            return False, err

    def init(self, action, detail_obj_list):
        """ 初始化服务 """
        # 获取初始化使用参数
        with ThreadPoolExecutor(THREAD_POOL_MAX_WORKERS) as executor:
            future_list = []
            for detail_obj in detail_obj_list:
                target_ip = detail_obj.service.ip
                service_name = detail_obj.service.service_instance_name
                service_controllers_dict = detail_obj.service.service_controllers
                if target_ip not in self.target_set:
                    # 中间结果,全部成功后更新状态
                    self.detail_dict[detail_obj] = service_name
                    self.target_set.add(target_ip)
                    logger.info(f"Init Begin -> [{service_name}]")
                    detail_obj.init_flag = 1
                    detail_obj.init_msg += f"{self.install_obj.now_time()} {service_name} 开始初始化服务\n"
                    detail_obj.save()
                future_obj = executor.submit(
                    self.init_hadoop, detail_obj,
                    target_ip, service_controllers_dict,
                    action
                )
                future_list.append(future_obj)
            self.check_result(future_list)
        # 安装成功
        if self.count == 9:
            for obj, name in self.detail_dict.items():
                logger.info(f"Init Success -> [{name}]")
                obj.init_flag = 2
                obj.init_msg += f"{self.install_obj.now_time()} {name} 成功初始化服务\n"
                # 完成安装流程,更新状态为 '安装成功'
                obj.install_step_status = \
                    DetailInstallHistory.INSTALL_STATUS_SUCCESS
                # 创建历史记录
                self.install_obj.create_history(obj, is_success=True)
            return True, "Init Success"

    def single_service_executor(self, detail_obj):
        """
        单独服务的安装执行器
        :param detail_obj:
        :type detail_obj: DetailInstallHistory
        :return:
        """
        # 更改服务状态为安装中状态
        detail_obj.service.service_status = Service.SERVICE_STATUS_INSTALLING
        detail_obj.service.save()
        # 跳过单个服务的已经成功的单个步骤不再重复执行
        for action in self.ACTION_LS:
            if getattr(detail_obj, f"{action}_flag") == 2:
                continue
            _flag, _msg = getattr(self.install_obj, action)(detail_obj)
            if not _flag:
                return _flag, _msg
        return True, "success"

    def sync_port(self, service_obj):
        """
        同步要监控的port
        """
        ports = json.loads(service_obj.service_port)
        role_key = {
            "namenode_rpc_port": "namenode",
            "journalnode_rpc_port": "journalnode",
            "resourcemanager_webapp_port": "resourcemanager",
            "nodemanager_port": "nodemanager",
            "datanode_rpc_port": "datanode",
            "zkfc_rpc_port": "zkfc",
            "secondarynamenode_rpc_port": "secondarynamenode"
        }
        for port in ports:
            port_key = role_key.get(port.get("key", ""))
            if port_key:
                self.port[port_key] = port.get("default", "")

    def sync_dir(self, obj_list):
        for detail in obj_list:
            install_file = detail.service.service_controllers.get(
                "install", "")
            if install_file:
                install_file = install_file.replace("install.py", "hadoop")
            self.base_dir[detail.service.ip] = install_file

    def _get_service_port(self, role):
        port = self.port.get(role, "")
        port_json = [{
            "name": role,
            "protocol": "TCP",
            "key": "service_port",
            "default": port
        }]
        return json.dumps(port_json, ensure_ascii=False)

    def _get_service_controllers(self, ip, role):
        script_dir = self.base_dir.get(ip, "").split()[0]
        controllers = {
            "init": "",
            "start": f"{script_dir} start {role}",
            "stop": f"{script_dir} stop {role}",
            "restart": f"{script_dir} restart {role}",
            "install": ""
        }
        return controllers

    def _create_service(self, role, detail_obj):
        ip = detail_obj.service.ip
        instance_name = role + "_" + "_".join(ip.split(".")[2:])
        # if "secondarynamenode" in detail_obj.service.service_role:
        #    cluster = ClusterInfo.objects.get_or_create(
        #        cluster_service_name="hadoop",
        #        cluster_name=detail_obj.service.service_instance_name,
        #    )[0]
        # else:
        #    cluster = detail_obj.service.cluster
        service_obj = Service.objects.create(
            ip=ip,
            service_instance_name=instance_name,
            service_status=0,
            service=detail_obj.service.service,
            service_port=self._get_service_port(role),
            service_controllers=self._get_service_controllers(ip, role),
            # cluster=cluster,
            env=detail_obj.service.env,
            service_split=2
        )
        # TODO 操作用户
        ServiceHistory.objects.create(
            username="admin",
            description="安装服务",
            result="success",
            service=service_obj)
        Host.objects.filter(ip=ip).update(
            service_num=F("service_num") + 1)
        return service_obj

    def _create_detail(self, service_obj, detail_obj):
        """
        创建detail表
        """
        status = DetailInstallHistory.INSTALL_STATUS_SUCCESS
        DetailInstallHistory.objects.create(
            service=service_obj,
            main_install_history=detail_obj.main_install_history,
            install_step_status=status,
            send_flag=status,
            unzip_flag=status,
            install_flag=status,
            init_flag=status,
            start_flag=status,
            post_action_flag=status,
            install_detail_args=detail_obj.install_detail_args
        )

    def high_thread_executor(self):
        """
        多线程执行器
        """
        logger.info(f"Start thread poll executor for {self.detail_list}")
        with ThreadPoolExecutor(THREAD_POOL_MAX_WORKERS) as executor:
            _future_list = []
            for detail_obj in self.detail_list:
                # 更新单条安装记录的状态
                detail_obj.install_step_status = \
                    DetailInstallHistory.INSTALL_STATUS_INSTALLING
                detail_obj.save()
                future_obj = executor.submit(
                    self.single_service_executor, detail_obj
                )
                _future_list.append(future_obj)
            self.check_result(_future_list)
            for action in self.hadoop_init:
                if not self.error:
                    self.init(action, self.detail_list)
        if not self.error:
            # 创建表数据
            with transaction.atomic():
                self.sync_port(self.detail_list[0].service)
                self.sync_dir(self.detail_list)
                for obj in self.detail_list:
                    host_ip = obj.service.ip
                    roles_name = obj.service.service_role
                    for role in roles_name.split(","):
                        ser_obj = self._create_service(role, obj)
                        self._create_detail(ser_obj, obj)
                    obj.service.service_status = Service.SERVICE_STATUS_UNKNOWN
                    obj.service.service_split = 1
                    obj.service.save()
                    # obj.service.delete()
                    # 更新拆分前服务detail状态
                    obj.install_step_status = DetailInstallHistory.INSTALL_STATUS_SUCCESS
                    obj.save()
                    Host.objects.filter(ip=host_ip).update(
                        service_num=F("service_num") - 1)
            logger.info("Finish thread poll executor!")


================================================
FILE: omp_server/app_store/install_exec.py
================================================
"""
安装执行器
前提:所有的公共组件都由OMP进行安装处理
目标:根据数据库中给出的安装记录进行服务安装
"""
import copy
import json
import os
import time
import queue
import logging
import re
from concurrent.futures import (
    ThreadPoolExecutor, as_completed
)
# from django.db.models import F
from django.conf import settings

from app_store.high_availability_utils import HIGH_AVAILABILITY_UTILS
from db_models.models import (
    Host, Service, HostOperateLog, ServiceHistory,
    MainInstallHistory, DetailInstallHistory, ApplicationHub,
    PreInstallHistory, PostInstallHistory
)
from utils.plugin.salt_client import SaltClient
from utils.parse_config import BASIC_ORDER
from utils.parse_config import THREAD_POOL_MAX_WORKERS
from utils.common.exceptions import GeneralError
from omp_server.settings import PROJECT_DIR
from app_store.post_install_utils import POST_INSTALL_SERVICE
from app_store.service_splitting import service_splitting

UNZIP_CONCURRENT_ONE_HOST = 3
OPENSSL_VERSION_LEVEL = 102
DOIM_APP_NAME = 'doim'
logger = logging.getLogger("server")


class InstallServiceExecutor:
    """ 安装服务执行器 """
    ACTION_LS = ("send", "unzip", "install", "init", "start")

    def __init__(self, main_id, username, timeout=300):
        self.main_id = main_id
        self.username = username
        self.timeout = timeout
        # 安装中是否发生错误,用于流程控制
        self.is_error = False
        # 控制安装过程中单主机上的安装包解压并发数 TODO 暂时使用阻塞等待方式进行处理!!
        self.unzip_concurrent_controller = dict()

    def parse_origin_data(self, json_source_path):
        """
        解析数据
        :param json_source_path:
        :return:
        """
        _file_name = os.path.join(PROJECT_DIR, "package_hub", json_source_path)
        with open(_file_name, "r") as fp:
            content = json.loads(fp.read())
            if not isinstance(content, list):
                raise GeneralError("json文件不符合格式要求!")
        ip_user_map = dict()
        for item in content:
            if item["ip"] not in ip_user_map:
                ip_user_map[item["ip"]] = list()
            if "install_args" not in item:
                continue
            for el in item["install_args"]:
                if el.get("key") == "run_user" and el.get("default"):
                    ip_user_map[item["ip"]].append(el.get("default"))
                    break
        return ip_user_map

    def set_hostname_analysis(self, ips_data, ip, salt_client):
        test_write_host_func = "cat /tmp/init_host.py | grep write_hostname"
        flag, msg = salt_client.cmd(
            target=ip,
            command=test_write_host_func,
            timeout=60
        )
        logger.info(f"测试主机[{ip}]init_host.py脚本write_host功能,结果 {msg}")
        if not flag or "write_hostname" not in msg:
            is_success, message = salt_client.cp_file(
                target=ip,
                source_path="_modules/init_host.py",
                target_path="/tmp/init_host.py"
            )
            logger.info(f"主机[{ip}]发送init_host.py脚本成功!")
            if not is_success:
                return f"{self.now_time()} 执行主机名解析失败!请手动添加集群主机名解析!\n"
        host_data = []
        for k, v in ips_data.items():
            if not v.get("host_name"):
                logger.error(f"未获取到主机[{ip}]的主机名,添加主机名解析失败!")
                return f"未获取到主机[{ip}]的主机名,添加主机名解析失败!" \
                       f"请重启主机agent重试或手动添加主机名解析"
            host_data.append({"ip": k, "hostname": v.get("host_name")})
        hosts_data = json.dumps(host_data, separators=(',', ':'))
        # 直接用sudo执行,报错即进行警告
        write_host = f"sudo python /tmp/init_host.py write_hostname '{hosts_data}'"
        flag, msg = salt_client.cmd(
            target=ip,
            command=write_host,
            timeout=60
        )
        if not flag:
            return f"{self.now_time()} 执行主机名解析失败!请手动添加集群主机名解析!\n"
        return f"{self.now_time()} 执行主机名解析成功!\n"

    def _execute_pre_install(
            self, ips_data,
            key, value, main_obj,
            json_source_path, salt_client, pre_install_obj
    ):
        """

        :param ips_data:
        :param key:
        :param value:
        :param main_obj:
        :param json_source_path:
        :param salt_client:
        :param pre_install_obj:
        :return:
        """
        try:
            message = self.set_hostname_analysis(ips_data, key, salt_client)
        except Exception as e:
            logger.error(f"执行主机名解析报错:{str(e)}")
            message = f"{self.now_time()} 执行主机名解析失败!请手动添加集群主机名解析!\n"
        pre_install_obj.install_log += message
        pre_install_obj.save()

        json_target_path = os.path.join(
            ips_data[key].get("data_folder", "/data"),
            f"omp_packages/{main_obj.operation_uuid}.json")
        pre_install_obj.install_log += f"{self.now_time()} 开始发送json文件\n"
        pre_install_obj.save()
        # 发送 json 文件
        is_success, message = salt_client.cp_file(
            target=key,
            source_path=json_source_path,
            target_path=json_target_path)
        if not is_success:
            pre_install_obj.install_log += \
                f"{self.now_time()} 发送json文件失败: {message}\n"
            pre_install_obj.install_flag = 3
            pre_install_obj.save()
            raise GeneralError(f"发送 json 文件失败: {message}")
        for el in set(value):
            _cmd = f"id {el} || useradd -s /bin/bash {el}"
            pre_install_obj.install_log += \
                f"{self.now_time()} 开始执行创建用户命令: {_cmd}\n"
            pre_install_obj.save()
            flag, msg = salt_client.cmd(
                target=key,
                command=_cmd,
                timeout=60
            )
            logger.info(f"为主机 [{key}] 创建用户 [{el}] 结果 {msg}")
            if not flag:
                pre_install_obj.install_log += \
                    f"{self.now_time()} 创建用户命令执行失败: {msg}\n"
                pre_install_obj.install_flag = 3
                pre_install_obj.save()
                raise GeneralError(f"为主机 [{key}] 创建用户 [{el}] 失败!")
        # 适配doim
        doim_queryset = DetailInstallHistory.objects.select_related(
            "service", "service__service"
        ).filter(main_install_history_id=self.main_id, service__service__app_name__iexact=DOIM_APP_NAME).exclude(
            install_step_status=DetailInstallHistory.INSTALL_STATUS_SUCCESS)
        doim_ips = set([item.service.ip for item in doim_queryset])
        pre_install_obj.install_log += \
            f"{self.now_time()} 升级openssl version参数位:[doim_queryset] == {doim_queryset};[key]={key}; [doim_ips]={doim_ips}\n"
        pre_install_obj.save()
        if doim_queryset and key in doim_ips:
            # 1.run_user 必须为root
            if "root" not in value:
                pre_install_obj.install_log += \
                    f"{self.now_time()} 安装doim执行失败,用户[{value}]为非root\n"
                pre_install_obj.install_flag = 3
                pre_install_obj.save()
                raise GeneralError(
                    f"主机 [{key}] 的run_user[{value}]为非root,不支持doim安装")
            # 2.获取openssl版本号
            openssl_version_cmd = "openssl version"
            ssl_version = self.get_openssl_version_from_cmd(ip=key, salt_client=salt_client,
                                                            cmd_str=openssl_version_cmd)
            if ssl_version < OPENSSL_VERSION_LEVEL:
                pre_install_obj.install_log += f"{self.now_time()} 当前系统的openssl version 为{ssl_version}; 开始升级openssl version\n"
                pre_install_obj.save()
                upgrade_flag, upgrade_msg = self.upgrade_openssl(
                    ip=key, salt_client=salt_client)
                if not upgrade_flag:
                    pre_install_obj.install_log += \
                        f"{self.now_time()} 升级openssl version执行失败: {upgrade_msg}\n"
                    pre_install_obj.install_flag = 3
                    pre_install_obj.save()
                    raise GeneralError(f"为主机 [{key}] 升级openssl version执行失败!")
                pre_install_obj.install_log += f"{self.now_time()} 当前系统的openssl version成功升级\n"
                pre_install_obj.save()

        pre_install_obj.install_log += \
            f"{self.now_time()} 前置安装操作完成\n"
        pre_install_obj.install_flag = 2
        pre_install_obj.save()

    def create_user_and_send_json(self, main_obj):
        """
        下发json文件并创建run_user用户
        :return:
        """
        # 获取 json 文件路径
        salt_client = SaltClient()
        json_source_path = os.path.join(
            "data_files",
            f"{main_obj.operation_uuid}.json")
        ips_data = {
            host["ip"]: host for host in list(
                Host.objects.all().values(
                    "ip", "data_folder", "username", "host_name"
                )
            )
        }

        ip_user_map = self.parse_origin_data(json_source_path)
        for key, value in ip_user_map.items():
            pre_install_obj = PreInstallHistory.objects.filter(
                main_install_history=main_obj, ip=key
            ).last()
            if not pre_install_obj or pre_install_obj.install_flag == 2:
                continue
            try:
                pre_install_obj.install_flag = 1
                pre_install_obj.install_log += \
                    f"{self.now_time()} 开始执行前置安装操作\n"
                pre_install_obj.save()
                self._execute_pre_install(
                    ips_data, key, value, main_obj,
                    json_source_path, salt_client, pre_install_obj
                )
            except GeneralError as e:
                pre_install_obj.install_log += \
                    f"{self.now_time()} 前置安装操作失败: {str(e)}\n"
                pre_install_obj.install_flag = 3
                pre_install_obj.save()

    @staticmethod
    def now_time():
        """ 当前时间格式 """
        return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())

    def create_history(self, detail_obj, is_success=True):
        """ 创建历史记录 """
        target_ip = detail_obj.service.ip
        service_name = detail_obj.service.service_instance_name
        # 写入主机历史记录、服务历史记录
        target_host = Host.objects.filter(ip=target_ip).first()
        HostOperateLog.objects.create(
            username=self.username,
            description=f"安装服务 [{service_name}]",
            result="success" if is_success else "failed",
            host=target_host)
        ServiceHistory.objects.create(
            username=self.username,
            description="安装服务",
            result="success" if is_success else "failed",
            service=detail_obj.service)
        # 主机服务数量+1
        # 屏蔽安装完成后服务数 +1 逻辑
        # if is_success:
        #     Host.objects.filter(ip=target_ip).update(
        #         service_num=F("service_num") + 1)

    def send(self, detail_obj):
        """ 发送服务包 """
        # 获取发送使用参数
        salt_client = SaltClient()
        target_ip = detail_obj.service.ip
        service_name = detail_obj.service.service_instance_name
        package_name = detail_obj.service.service.app_package.package_name

        # 更新状态为 '发送中',记录日志
        logger.info(f"Send Begin -> [{service_name}] package [{package_name}]")
        detail_obj.send_flag = 1
        detail_obj.send_msg += f"{self.now_time()} {service_name} 开始发送服务包\n"
        detail_obj.save()

        try:
            # 获取目标路径
            target_host = Host.objects.filter(ip=target_ip).first()
            assert target_host is not None

            # 获取 json 文件路径 已将json发送前置  jon.liu
            # json_source_path = os.path.join(
            #     "data_files",
            #     f"{detail_obj.main_install_history.operation_uuid}.json")
            # json_target_path = os.path.join(
            #     target_host.data_folder, "omp_packages",
            #     f"{detail_obj.main_install_history.operation_uuid}.json")
            #
            # # 发送 json 文件
            # is_success, message = salt_client.cp_file(
            #     target=target_ip,
            #     source_path=json_source_path,
            #     target_path=json_target_path)
            # if not is_success:
            #     raise GeneralError(f"发送 json 文件失败: {message}")

            # 获取服务包路径
            source_path = os.path.join(
                detail_obj.service.service.app_package.package_path,
                package_name)
            target_path = os.path.join(
                target_host.data_folder, "omp_packages",
                package_name)

            # 发送服务包
            is_success, message = salt_client.cp_file(
                target=target_ip,
                source_path=source_path,
                target_path=target_path)
            if not is_success:
                raise GeneralError(message)

        except Exception as err:
            logger.error(f"Send Failed -> [{service_name}]: {err}")
            detail_obj.send_flag = 3
            detail_obj.send_msg += f"{self.now_time()} {service_name} " \
                                   f"发送服务包失败: {err}\n"
            detail_obj.install_step_status = \
                DetailInstallHistory.INSTALL_STATUS_FAILED
            detail_obj.save()
            detail_obj.service.service_status = \
                Service.SERVICE_STATUS_INSTALL_FAILED
            detail_obj.service.save()
            # 创建历史记录
            self.create_history(detail_obj, is_success=False)
            return False, err
        # 发送成功
        logger.info(
            f"Send Success -> [{service_name}] package [{package_name}]")
        detail_obj.send_flag = 2
        detail_obj.send_msg += f"{self.now_time()} {service_name} 成功发送服务包\n"
        detail_obj.save()
        return True, "Send Success"

    def unzip(self, detail_obj):
        """ 解压服务包 """
        # 获取解压使用参数
        target_ip = detail_obj.service.ip
        service_name = detail_obj.service.service_instance_name
        package_name = detail_obj.service.service.app_package.package_name
        salt_client = SaltClient()

        # 更新状态为 '解压中',记录日志
        logger.info(
            f"Unzip Begin -> [{service_name}] package [{package_name}]")
        detail_obj.unzip_flag = 1
        detail_obj.unzip_msg += f"{self.now_time()} {service_name} 开始解压服务包\n"
        detail_obj.save()

        try:
            # 控制单主机上的服务包解压操作,向控制队列中添加一项
            # 如果能加入成功则继续,否则等待其加入成功
            self.unzip_concurrent_controller[target_ip].put(service_name)
            # 解析获取目录
            target_host = Host.objects.filter(ip=target_ip).first()
            assert target_host is not None
            package_path = os.path.join(
                target_host.data_folder, "omp_packages",
                package_name)
            # 获取解压目标路径
            detail_args = detail_obj.install_detail_args
            assert detail_args is not None
            app_name = detail_args.get("name", None)
            assert app_name is not None
            target_path = None
            for info in detail_args.get("install_args", []):
                if info.get("key", "") == "base_dir":
                    target_path = info.get("default")
                    break
            if target_path is None:
                raise GeneralError("未获取到解压目标路径")
            # 切分判断路径
            path_ls = os.path.split(target_path)
            # 创建服务目录,解压服务包
            if path_ls[1] == app_name:
                _target_path = path_ls[0]
                test_path_cmd_str = f"(test -d {_target_path} || mkdir -p {_target_path}) && " \
                                    f"tar -xmf {package_path} -C {_target_path}"
            else:
                # 当路径结尾与服务名不一致时
                _target_path = path_ls[0]
                real_path = os.path.join(_target_path, app_name)
                test_path_cmd_str = f"(test -d {_target_path} || mkdir -p {_target_path}) && " \
                                    f"tar -xmf {package_path} -C {_target_path} && mv {real_path} {target_path}/"
            is_success, message = salt_client.cmd(
                target=target_ip,
                command=test_path_cmd_str,
                timeout=self.timeout)
            if not is_success:
                raise GeneralError(message)

        except Exception as err:
            # 解压流程运行完成后报错,释放资源
            self.unzip_concurrent_controller[target_ip].get()
            logger.error(f"Unzip Failed -> [{service_name}]: {err}")
            detail_obj.unzip_flag = 3
            detail_obj.unzip_msg += \
                f"{self.now_time()} {service_name} " \
                f"解压服务包失败: {err}\n"
            detail_obj.install_step_status = \
                DetailInstallHistory.INSTALL_STATUS_FAILED
            detail_obj.save()
            detail_obj.service.service_status = \
                Service.SERVICE_STATUS_INSTALL_FAILED
            detail_obj.service.save()
            # 创建历史记录
            self.create_history(detail_obj, is_success=False)
            return False, err
        # 解压流程运行完成后报错,释放资源
        self.unzip_concurrent_controller[target_ip].get()
        # 解压成功
        logger.info(
            f"Unzip Success -> [{service_name}] package [{package_name}]")
        detail_obj.unzip_flag = 2
        detail_obj.unzip_msg += \
            f"{self.now_time()} {service_name} 成功解压服务包\n"
        detail_obj.save()
        return True, "Unzip Success"

    def install(self, detail_obj):
        """ 安装服务 """
        # 获取安装使用参数
        salt_client = SaltClient()
        target_ip = detail_obj.service.ip
        service_name = detail_obj.service.service_instance_name
        app_name = detail_obj.service.service.app_name
        # edit by jon.liu service_controllers 为json字段,无需json.loads
        service_controllers_dict = detail_obj.service.service_controllers

        # 更新状态为 '安装中',记录日志
        logger.info(f"Install Begin -> [{service_name}]")
        detail_obj.install_flag = 1
        detail_obj.install_msg += \
            f"{self.now_time()} {service_name} 开始安装服务\n"
        detail_obj.save()

        try:
            # 获取服务安装脚本绝对路径
            install_script_path = service_controllers_dict.get("install", "")
            if install_script_path == "":
                raise GeneralError("未找到安装脚本路径")

            # 获取 json 文件路径
            target_host = Host.objects.filter(ip=target_ip).first()
            assert target_host is not None
            json_path = os.path.join(
                target_host.data_folder, "omp_packages",
                f"{detail_obj.main_install_history.operation_uuid}.json")

            cmd_str = f"python {install_script_path} --local_ip {target_ip} " \
                      f"--data_json {json_path}"
            # doim定制化安装
            if app_name.lower() == DOIM_APP_NAME:
                install_script_path = os.path.realpath(install_script_path)
                app_dir, script_name = os.path.split(install_script_path)
                doim_install_script_path = os.path.join(app_dir, 'install.sh')
                install_dir, _service_name = os.path.split(app_dir)
                cmd_str = f"sed -i -e \"s#InstallRoot=.*#InstallRoot={install_dir}/DOIM #g\" -e \"s#char=.*#char=\"y\"#g\" {doim_install_script_path}; python {install_script_path} --local_ip {target_ip} " \
                          f"--data_json {json_path}"

            # 执行安装
            is_success, message = salt_client.cmd(
                target=target_ip,
                command=cmd_str,
                timeout=self.timeout)
            if not is_success:
                raise GeneralError(message)
            # 执行成功且 message 有值,则补充至服务日志中
            if is_success and bool(message):
                detail_obj.install_msg += \
                    f"{self.now_time()} 安装脚本执行成功,脚本输出如下:\n" \
                    f"{message}\n"
                detail_obj.save()
        except Exception as err:
            logger.error(f"Install Failed -> [{service_name}]: {err}")
            detail_obj.install_flag = 3
            detail_obj.install_msg += f"{self.now_time()} {service_name} " \
                                      f"安装服务失败: {err}\n"
            detail_obj.install_step_status = \
                DetailInstallHistory.INSTALL_STATUS_FAILED
            detail_obj.save()
            detail_obj.service.service_status = \
                Service.SERVICE_STATUS_INSTALL_FAILED
            detail_obj.service.save()
            # 创建历史记录
            self.create_history(detail_obj, is_success=False)
            return False, err

        # 安装成功
        logger.info(f"Install Success -> [{service_name}]")
        detail_obj.install_flag = 2
        detail_obj.install_msg += \
            f"{self.now_time()} {service_name} 成功安装服务\n"
        detail_obj.save()
        return True, "Install Success"

    def init(self, detail_obj):
        """ 初始化服务 """
        # 获取初始化使用参数
        salt_client = SaltClient()
        target_ip = detail_obj.service.ip
        service_name = detail_obj.service.service_instance_name
        service_controllers_dict = detail_obj.service.service_controllers

        # 更新状态为 '初始化中',记录日志
        logger.info(f"Init Begin -> [{service_name}]")
        detail_obj.init_flag = 1
        detail_obj.init_msg += f"{self.now_time()} {service_name} 开始初始化服务\n"
        detail_obj.save()

        try:
            # 获取服务初始化脚本绝对路径
            init_script_path = service_controllers_dict.get("init", "")
            if init_script_path == "":
                logger.info(f"Init Un Do -> [{service_name}]")
                detail_obj.init_flag = 2
                detail_obj.init_msg += \
                    f"{self.now_time()} {service_name} 无需执行初始化\n"
                # 完成安装流程,更新状态为 '安装成功'
                detail_obj.install_step_status = \
                    DetailInstallHistory.INSTALL_STATUS_SUCCESS
                detail_obj.save()
                # 创建历史记录
                self.create_history(detail_obj, is_success=True)
                return True, "Init Un Do"

            # 获取 json 文件路径
            target_host = Host.objects.filter(ip=target_ip).first()
            assert target_host is not None
            json_path = os.path.join(
                target_host.data_folder, "omp_packages",
                f"{detail_obj.main_install_history.operation_uuid}.json")

            cmd_str = f"python {init_script_path} --local_ip {target_ip} " \
                      f"--data_json {json_path}"
            # 执行初始化
            is_success, message = salt_client.cmd(
                target=target_ip,
                command=cmd_str,
                timeout=self.timeout)
            if not is_success:
                raise GeneralError(message)
            # 执行成功且 message 有值,则补充至服务日志中
            if is_success and bool(message):
                detail_obj.install_msg += \
                    f"{self.now_time()} 初始化脚本执行成功,脚本输出如下:\n" \
                    f"{message}\n"
                detail_obj.save()
        except Exception as err:
            logger.error(f"Init Failed -> [{service_name}]: {err}")
            detail_obj.init_flag = 3
            detail_obj.init_msg += f"{self.now_time()} {service_name} " \
                                   f"初始化服务失败: {err}\n"
            # 更新安装流程状态为 '失败',服务状态为 '安装失败'
            detail_obj.install_step_status = \
                DetailInstallHistory.INSTALL_STATUS_FAILED
            detail_obj.save()
            detail_obj.service.service_status = \
                Service.SERVICE_STATUS_INSTALL_FAILED
            detail_obj.service.save()
            # 创建历史记录
            self.create_history(detail_obj, is_success=False)
            return False, err
        # 安装成功
        logger.info(f"Init Success -> [{service_name}]")
        detail_obj.init_flag = 2
        detail_obj.init_msg += f"{self.now_time()} {service_name} 成功初始化服务\n"
        # 完成安装流程,更新状态为 '安装成功'
        # 如果是自研服务,初始化完成即认为其安装成功
        if detail_obj.service.service.app_type == \
                ApplicationHub.APP_TYPE_SERVICE:
            detail_obj.install_step_status = \
                DetailInstallHistory.INSTALL_STATUS_SUCCESS
            detail_obj.save()
        # 创建历史记录
        self.create_history(detail_obj, is_success=True)
        return True, "Init Success"

    def start(self, detail_obj):
        """ 启动服务 """
        # 获取启动使用参数
        salt_client = SaltClient()
        target_ip = detail_obj.service.ip
        service_name = detail_obj.service.service_instance_name
        service_controllers_dict = detail_obj.service.service_controllers

        # 更新状态为 '启动中',记录日志
        logger.info(f"Start Begin -> [{service_name}]")
        detail_obj.start_flag = 1
        detail_obj.start_msg += f"{self.now_time()} {service_name} 开始启动服务\n"
        detail_obj.save()

        try:
            # 获取服务启动脚本绝对路径
            start_script_path = service_controllers_dict.get("start", "")
            if start_script_path == "":
                logger.info(f"Start Un Do -> [{service_name}]")
                detail_obj.start_flag = 2
                detail_obj.start_msg += \
                    f"{self.now_time()} {service_name} 无需执行启动\n"
                # 如果服务无需启动,则认可其为安装成功
                detail_obj.install_step_status = \
                    DetailInstallHistory.INSTALL_STATUS_SUCCESS
                # 服务状态更新为 '正常'
                detail_obj.service.service_status = \
                    Service.SERVICE_STATUS_NORMAL
                detail_obj.service.save()
                detail_obj.save()
                return True, "Start Un Do"

            if "start" not in start_script_path:
                start_script_path += " start"
            cmd_str = f"bash {start_script_path}"

            # 执行启动
            is_success, message = salt_client.cmd(
                target=target_ip,
                command=cmd_str,
                timeout=self.timeout,
                real_timeout=self.timeout
            )
            if not is_success:
                raise GeneralError(message)
            result_str = message.upper()
            if "FAILED" in result_str or \
                    "NO RUNNING" in result_str or \
                    "NOT RUNNING" in result_str:
                raise GeneralError(message)
            # 执行成功且 message 有值,则补充至服务日志中
            if is_success and bool(message):
                detail_obj.install_msg += \
                    f"{self.now_time()} 启动脚本执行成功,脚本输出如下:\n" \
                    f"{message}\n"
                detail_obj.save()
        except Exception as err:
            logger.error(f"Start Failed -> [{service_name}]: {err}")
            detail_obj.start_flag = 3
            detail_obj.start_msg += f"{self.now_time()} {service_name} " \
                                    f"启动服务失败: {err}\n"
            # 如果是基础组件服务的启动步骤,如果启动失败则认为其安装失败
            if detail_obj.service.service.app_type == \
                    ApplicationHub.APP_TYPE_COMPONENT:
                detail_obj.install_step_status = \
                    DetailInstallHistory.INSTALL_STATUS_FAILED
            detail_obj.save()
            # 服务状态更新为 '停止'
            detail_obj.service.service_status = \
                Service.SERVICE_STATUS_STOP
            detail_obj.service.save()
            return False, err
        # 安装成功
        logger.info(f"Start Success -> [{service_name}]")
        detail_obj.start_flag = 2
        detail_obj.start_msg += f"{self.now_time()} {service_name} 成功启动服务\n"
        detail_obj.save()
        # 服务状态更新为 '正常'
        detail_obj.service.service_status = \
            Service.SERVICE_STATUS_NORMAL
        # 服务启动成功,则认为其已经安装成功
        detail_obj.install_step_status = \
            DetailInstallHistory.INSTALL_STATUS_SUCCESS
        detail_obj.save()
        detail_obj.service.save()
        return True, "Start Success"

    def execute_post_action(self, queryset, post_obj):  # NOQA
        """
        执行安装后的操作,所有服务安装完成后,针对不同服务的个性化配置执行
        目前仅支持shell脚本方式
        :param queryset: 包含部署详情表的列表
        :type queryset: [DetailInstallHistory]
        :param post_obj:
        :return:
        """
        try:
            salt_client = SaltClient()
            for detail_obj in queryset:
                target_ip = detail_obj.service.ip
                _script = detail_obj.service.service_controllers.get(
                    "post_action")
                command = f"chmod +x {_script.split()[0]} && {_script}"
                post_obj.install_log += \
                    f"{self.now_time()} 在{target_ip}节点执行 {command}\n"
                post_obj.save()
                flag, msg = salt_client.cmd(
                    target=target_ip,
                    command=command,
                    timeout=60
                )
                post_obj.install_log += \
                    f"{self.now_time()} " \
                    f"在{target_ip}节点执行 {command} 标志为: {flag}; 结果为: {msg}\n"
                post_obj.save()
                logger.info(f"Execute {_script}, flag: {flag}; msg: {msg}")
                detail_obj.post_action_msg += str(msg)
                if not flag:
                    self.is_error = True
                    detail_obj.post_action_flag = 3
                    detail_obj.save()
                    post_obj.install_flag = 3
                    post_obj.save()
                    break
                detail_obj.post_action_flag = 2
                detail_obj.save()
        except Exception as e:
            logger.error(f"Error while execute post_action: {str(e)}")
            self.is_error = True
            post_obj.install_flag = 3
            post_obj.save()

    def single_service_executor(self, detail_obj):
        """
        单独服务的安装执行器
        :param detail_obj:
        :type detail_obj: DetailInstallHistory
        :return:
        """
        # 更改服务状态为安装中状态
        detail_obj.service.service_status = Service.SERVICE_STATUS_INSTALLING
        detail_obj.service.save()
        # 针对单个服务执行循环("send", "unzip", "install", "init", "start")
        # 跳过单个服务的已经成功的单个步骤不再重复执行
        for action in self.ACTION_LS:
            if getattr(detail_obj, f"{action}_flag") == 2:
                continue
            _flag, _msg = getattr(self, action)(detail_obj)
            if not _flag:
                return _flag, _msg
        return True, "success"

    def high_availability_executor(self, detail_obj_lst):
        """
        过滤专属高可用阻塞部署
        :param detail_obj_lst: [detail_obj, detail_obj]
        :return:
        """
        deep_detail_obj_lst = copy.deepcopy(detail_obj_lst)
        tmp_dict = {}
        for detail_obj in deep_detail_obj_lst:
            app_name = detail_obj.service.service.app_name
            if app_name in HIGH_AVAILABILITY_UTILS.keys():
                tmp_dict[app_name] = tmp_dict.get(app_name, []) + [detail_obj]
                detail_obj_lst.remove(detail_obj)
        for name, obj in tmp_dict.items():
            # TODO 这个需要多线程处理
            HIGH_AVAILABILITY_UTILS[name](self, obj).high_thread_executor()
        return detail_obj_lst

    def thread_poll_executor(self, detail_obj_lst):
        """
        多线程执行器
        :param detail_obj_lst: [detail_obj, detail_obj]
        :return:
        """
        logger.info(f"Start thread poll executor for {detail_obj_lst}")
        # 阻塞部署hadoop等
        detail_obj_lst = self.high_availability_executor(detail_obj_lst)
        with ThreadPoolExecutor(THREAD_POOL_MAX_WORKERS) as executor:
            _future_list = []
            for detail_obj in detail_obj_lst:
                # 更新单条安装记录的状态
                detail_obj.install_step_status = \
                    DetailInstallHistory.INSTALL_STATUS_INSTALLING
                detail_obj.save()
                future_obj = executor.submit(
                    self.single_service_executor, detail_obj
                )
                _future_list.append(future_obj)
            for future in as_completed(_future_list):
                is_success, message = future.result()
                if not is_success:
                    self.is_error = True
                    break
        logger.info("Finish thread poll executor!")

    @staticmethod
    def make_install_order(queryset):
        """
        对所有的安装对象进行排序处理,控制其安装顺序
        :param queryset: 即将部署的详情对象组成的列表
        :return:
        """
        # 安装顺序的二维数组
        execute_lst = list()
        # 对基础组件进行排序处理,其中基础配置中的 BASIC_ORDER 为基础组件的排序等级
        # 如果有其他组件需要安装,怎需要在配置中进行额外的配置
        for i in range(10):
            if i not in BASIC_ORDER:
                break
            _lst = [
                el for el in queryset
                if el.service.service.app_name in BASIC_ORDER[i]
            ]
            execute_lst.append(_lst)
        # 对自研服务进行排序处理,先过滤出自研服务的列表
        _ser = [
            el for el in queryset
            if el.service.service.app_type == ApplicationHub.APP_TYPE_SERVICE
        ]
        # 自研服务level级别为0的服务,仅依赖于基础组件,无其他依赖
        execute_lst.append(
            [
                el for el in _ser if
                str(el.service.service.extend_fields.get("level")) == "0"]
        )
        # 自研服务level级别为1或其他的服务
        # 可依赖基础组件,也可依赖其他自研服务,文件级别位置依赖
        execute_lst.append(
            [
                el for el in _ser if
                str(el.service.service.extend_fields.get("level")) != "0"]
        )
        return execute_lst

    def execute_post_action_main(self, main_obj):
        """
        执行注册操作 post_action
        :param main_obj:
        :return:
        """
        post_obj = PostInstallHistory.objects.filter(
            main_install_history=main_obj
        ).last()
        if not post_obj:
            logger.info("No need execute post action!")
            return True, "success"
        # 安装后执行动作范围过滤,排除无需执行操作以及排除已经执行成功的服务对象
        # 判断整体执行安装完成后才执行
        if not DetailInstallHistory.objects.filter(
                install_step_status=DetailInstallHistory.INSTALL_STATUS_FAILED,
                main_install_history_id=self.main_id
        ).exists() and not self.is_error:
            post_action_queryset = DetailInstallHistory.objects.select_related(
                "service", "service__service",
                "service__service__app_package"
            ).filter(main_install_history_id=self.main_id).exclude(
                post_action_flag__in=[2, 4]
            )
            main_obj.install_status = \
                MainInstallHistory.INSTALL_STATUS_REGISTER
            main_obj.save()
            self.execute_post_action(post_action_queryset, post_obj)
        if not self.is_error:
            post_obj.install_flag = 2
            post_obj.save()
            return True, "success"
        post_obj.install_flag = 3
        post_obj.save()
        return False, "failed"

    def execute_pre_install(self, main_obj):
        """
        执行前置安装入口
        :param main_obj:
        :return:
        """
        try:
            self.create_user_and_send_json(main_obj)
        except Exception as e:
            logger.error(f"Pre-install failed: {str(e)}")
        if PreInstallHistory.objects.filter(
                main_install_history=main_obj,
                install_flag__in=[0, 1, 3]
        ).exists():
            return False
        return True

    def execute_post_install(self, main_obj):
        """
        执行安装后的操作,主要是针对nacos、tengine进行配置更新
        :param main_obj:
        :return:
        """
        post_obj = PostInstallHistory.objects.filter(
            main_install_history=main_obj
        ).last()
        if not post_obj:
            logger.info("No need execute post action!")
            return True, "success"
        if post_obj.install_flag == 2:
            return True, "success"
        post_obj.install_flag = 1
        post_obj.save()
        # 确定重新加载的服务 tengine & nacos & aopsUtils
        # if DetailInstallHistory.objects.filter(
        #         service__service__app_name__in=[
        #             "tengine", "nacos", "aopsUtils"]
        # ).exclude(main_install_history=main_obj).exists():
        #     for key, value in POST_INSTALL_SERVICE.items():
        #         if not DetailInstallHistory.objects.filter(
        #                 service__service__app_name=key).exclude(
        #             main_install_history=main_obj
        #         ).exists():
        #             continue
        #         post_obj.install_log += \
        #             f"{self.now_time()} 开始执行 {key} 安装后续任务\n"
        #         post_obj.save()
        #         _flag, _msg = value(main_obj=main_obj).run()
        #         post_obj.install_log += \
        #             f"{self.now_time()} " \
        #             f"{key} 安装后续任务执行标志: {_flag}; 执行结果为: {_msg}\n"
        #         post_obj.save()
        #         if not _flag:
        #             post_obj.install_flag = 3
        #             post_obj.save()
        #             return False, "execute post install action failed"

        # TODO 在增量安装的前提下,需要在加载nacos和tengine完成后,再启动其他自研服务
        if self.is_error:
            post_obj.install_flag = 3
            post_obj.save()
            return False, "service start failed"
        post_obj.install_flag = 2
        post_obj.save()
        return True, "success"

    @staticmethod
    def get_openssl_version_from_cmd(ip, salt_client, cmd_str):
        """获取openssl版本号"""
        ssl_flag, ssl_msg = salt_client.cmd(
            target=ip,
            command=cmd_str,
            timeout=60
        )
        str_os_version = ssl_msg.strip()
        res = re.findall(
            r'(.*?) ([0-9]+)\.([0-9]+)\.([0-9]+).*', str_os_version)
        str_version = "".join(res[0][1:]) if res else ""
        if not ssl_flag:
            return 0
        try:
            ssl_version = int(str_version)
        except ValueError:
            ssl_version = 0
        return ssl_version

    @staticmethod
    def upgrade_openssl(ip, salt_client):
        # 1.发送openssl升级包
        source_package_path = "openssl_upgrade/openssl-1.0.2k.tar.gz"
        dst_path = "/tmp/upgrade_openssl"
        dst_path_package = os.path.join(dst_path, "openssl-1.0.2k.tar.gz")
        package_flag, package_msg = salt_client.cp_file(
            target=ip,
            source_path=source_package_path,
            target_path=dst_path_package)
        if not package_flag:
            return False, package_msg
        # 2.发送openssl升级脚本
        source_script_path = "openssl_upgrade/upgrade_ssl.sh"
        dst_script_path = os.path.join(dst_path, "upgrade_ssl.sh")
        script_flag, script_msg = salt_client.cp_file(
            target=ip,
            source_path=source_script_path,
            target_path=dst_script_path)
        if not script_flag:
            return False, script_msg
        # 3.执行openssl升级脚本
        cmd_str = "cd /tmp/upgrade_openssl && chmod +x upgrade_ssl.sh && bash upgrade_ssl.sh"
        cmd_flag, cmd_msg = salt_client.cmd(
            target=ip,
            command=cmd_str,
            timeout=60
        )
        if not cmd_flag:
            return False, cmd_msg
        return True, "upgrade openssl success"

    def main(self):
        """ 主函数 """
        logger.info(f"Main Install Begin, id[{self.main_id}]")
        # 获取主表对象,更新状态为 '安装中'
        main_obj = MainInstallHistory.objects.filter(
            id=self.main_id).first()
        assert main_obj is not None
        main_obj.install_status = \
            MainInstallHistory.INSTALL_STATUS_INSTALLING
        main_obj.save()

        # 执行安装前的操作
        pre_install_flag = self.execute_pre_install(main_obj=main_obj)
        if not pre_install_flag:
            main_obj.install_status = MainInstallHistory.INSTALL_STATUS_FAILED
            main_obj.save()
            return

        # 执行安装后的操作
        _post_install_flag, _post_install_msg = self.execute_post_install(
            main_obj=main_obj
        )
        if not _post_install_flag:
            self.is_error = True
            main_obj.install_status = MainInstallHistory.INSTALL_STATUS_FAILED
            main_obj.save()
            return

        # 获取所有安装细节表,排除已经安装成功的记录,不再重复安装
        queryset = DetailInstallHistory.objects.select_related(
            "service", "service__service", "service__service__app_package"
        ).filter(main_install_history_id=self.main_id).exclude(
            install_step_status=DetailInstallHistory.INSTALL_STATUS_SUCCESS)
        # assert queryset.exists()

        # 构建 unzip_concurrent_controller 用于控制解压安装包时单主机的并发数量
        ips = set([el.service.ip for el in queryset])
        self.unzip_concurrent_controller = {
            el: queue.Queue(maxsize=UNZIP_CONCURRENT_ONE_HOST) for el in ips
        }

        # 所有子流程状态更新为 '待安装'
        queryset.update(
            install_step_status=DetailInstallHistory.INSTALL_STATUS_READY,
        )
        # 将要安装的服务实例更新为 '待安装'
        service_ids = queryset.values_list("service_id", flat=True)
        Service.objects.filter(
            id__in=service_ids
        ).update(service_status=Service.SERVICE_STATUS_READY)

        # 对要执行安装的列表进行排序处理
        tobe_execute_lst = self.make_install_order(queryset)
        logger.info(f"Tobe_execute_lst: {tobe_execute_lst}")
        for item in tobe_execute_lst:
            if not item:
                continue
            # 根据安装顺序每层并发执行
            self.thread_poll_executor(detail_obj_lst=item)
            # 如果哪层的服务有安装失败的情况,那么直接退出循环
            if self.is_error:
                break

        if self.is_error:
            # 步骤失败,主流程失败
            main_obj.install_status = \
                MainInstallHistory.INSTALL_STATUS_FAILED
            main_obj.save()
            # 安装完成后不再更改服务的状态
            # 状态为 '待安装'/'安装中' 的记录,则记为 '失败'
            # queryset.filter(install_step_status__in=(
            #     DetailInstallHistory.INSTALL_STATUS_READY,
            #     DetailInstallHistory.INSTALL_STATUS_INSTALLING
            # )).update(
            #     install_step_status=DetailInstallHistory.INSTALL_STATUS_FAILED
            # )
            logger.info(f"Main Install Failed, id[{self.main_id}]")
            return self.is_error

        post_flag, post_msg = self.execute_post_action_main(main_obj=main_obj)
        if not post_flag:
            main_obj.install_status = \
                MainInstallHistory.INSTALL_STATUS_FAILED
            main_obj.save()
            logger.error(f"Main Install Failed, id[{self.main_id}]")
            return self.is_error

        # 流程执行完整,主流程成功
        main_obj.install_status = \
            MainInstallHistory.INSTALL_STATUS_SUCCESS
        main_obj.save()
        # doim安装成功后,相关操作
        doim_ids = list(
            DetailInstallHistory.objects.filter(
                main_install_history_id=self.main_id,
                service__service_instance_name__startswith=DOIM_APP_NAME
            ).values_list("service_id", flat=True)
        )
        if doim_ids:
            service_splitting(doim_ids)
        logger.info(f"Main Install Success, id[{self.main_id}]")
        return self.is_error


================================================
FILE: omp_server/app_store/install_executor.py
================================================
"""
安装执行器
"""
import os
import time
import logging
from concurrent.futures import (
    ThreadPoolExecutor, as_completed
)
from django.db.models import F
from db_models.models import (
    Host, Service, HostOperateLog, ServiceHistory,
    MainInstallHistory, DetailInstallHistory
)
from utils.plugin.salt_client import SaltClient
from utils.parse_config import THREAD_POOL_MAX_WORKERS

logger = logging.getLogger("server")


class InstallServiceExecutor:
    """ 安装服务执行器 """
    ACTION_LS = ("send", "unzip", "install", "init", "start")

    def __init__(self, main_id, username, timeout=300):
        self.main_id = main_id
        self.username = username
        self.timeout = timeout
        # 安装中是否发生错误,用于流程控制
        self.is_error = False

    @staticmethod
    def now_time():
        return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())

    def create_history(self, detail_obj, is_success=True):
        """ 创建历史记录 """
        target_ip = detail_obj.service.ip
        service_name = detail_obj.service.service_instance_name
        # 写入主机历史记录、服务历史记录
        target_host = Host.objects.filter(ip=target_ip).first()
        HostOperateLog.objects.create(
            username=self.username,
            description=f"安装服务 [{service_name}]",
            result="success" if is_success else "failed",
            host=target_host)
        ServiceHistory.objects.create(
            username=self.username,
            description="安装服务",
            result="success" if is_success else "failed",
            service=detail_obj.service)
        # 主机服务数量+1
        if is_success:
            Host.objects.filter(ip=target_ip).update(
                service_num=F("service_num") + 1)

    def send(self, detail_obj):
        """ 发送服务包 """
        # 获取发送使用参数
        salt_client = SaltClient()
        target_ip = detail_obj.service.ip
        service_name = detail_obj.service.service_instance_name
        package_name = detail_obj.service.service.app_package.package_name

        # 更新状态为 '发送中',记录日志
        logger.info(f"Send Begin -> [{service_name}] package [{package_name}]")
        detail_obj.send_flag = 1
        detail_obj.send_msg += f"{self.now_time()} {service_name} 开始发送服务包\n"
        detail_obj.save()

        try:
            # 获取目标路径
            target_host = Host.objects.filter(ip=target_ip).first()
            assert target_host is not None

            # 获取 json 文件路径
            json_source_path = os.path.join(
                "data_files",
                f"{detail_obj.main_install_history.operation_uuid}.json")
            json_target_path = os.path.join(
                target_host.data_folder, "omp_packages",
                f"{detail_obj.main_install_history.operation_uuid}.json")

            # 发送 json 文件
            is_success, message = salt_client.cp_file(
                target=target_ip,
                source_path=json_source_path,
                target_path=json_target_path)
            if not is_success:
                raise Exception(f"发送 json 文件失败: {message}")

            # 获取服务包路径
            source_path = os.path.join(
                detail_obj.service.service.app_package.package_path,
                package_name)
            target_path = os.path.join(
                target_host.data_folder, "omp_packages",
                package_name)

            # 发送服务包
            is_success, message = salt_client.cp_file(
                target=target_ip,
                source_path=source_path,
                target_path=target_path)
            if not is_success:
                raise Exception(message)

        except Exception as err:
            logger.error(f"Send Failed -> [{service_name}]: {err}")
            detail_obj.send_flag = 3
            detail_obj.send_msg += f"{self.now_time()} {service_name} " \
                                   f"发送服务包失败: {err}\n"
            detail_obj.install_step_status = DetailInstallHistory.INSTALL_STATUS_FAILED
            detail_obj.save()
            detail_obj.service.service_status = Service.SERVICE_STATUS_INSTALL_FAILED
            detail_obj.service.save()
            # 创建历史记录
            self.create_history(detail_obj, is_success=False)
            return False, err
        # 发送成功
        logger.info(
            f"Send Success -> [{service_name}] package [{package_name}]")
        detail_obj.send_flag = 2
        detail_obj.send_msg += f"{self.now_time()} {service_name} 成功发送服务包\n"
        detail_obj.save()
        return True, "Send Success"

    def unzip(self, detail_obj):
        """ 解压服务包 """
        # 获取解压使用参数
        salt_client = SaltClient()
        target_ip = detail_obj.service.ip
        service_name = detail_obj.service.service_instance_name
        package_name = detail_obj.service.service.app_package.package_name

        # 更新状态为 '解压中',记录日志
        logger.info(
            f"Unzip Begin -> [{service_name}] package [{package_name}]")
        detail_obj.unzip_flag = 1
        detail_obj.unzip_msg += f"{self.now_time()} {service_name} 开始解压服务包\n"
        detail_obj.save()

        try:
            # 解析获取目录
            target_host = Host.objects.filter(ip=target_ip).first()
            assert target_host is not None
            package_path = os.path.join(
                target_host.data_folder, "omp_packages",
                package_name)
            # 获取解压目标路径
            detail_args = detail_obj.install_detail_args
            assert detail_args is not None
            app_name = detail_args.get("name", None)
            assert app_name is not None
            target_path = None
            for info in detail_args.get("install_args", []):
                if info.get("key", "") == "base_dir":
                    target_path = info.get("default")
                    break
            if target_path is None:
                raise Exception("未获取到解压目标路径")
            # 切分判断路径
            path_ls = os.path.split(target_path)
            # 创建服务目录,解压服务包
            if path_ls[1] == app_name:
                _target_path = path_ls[0]
                test_path_cmd_str = f"(test -d {_target_path} || mkdir -p {_target_path}) && " \
                                    f"tar -xmf {package_path} -C {_target_path}"
            else:
                # 当路径结尾与服务名不一致时
                _target_path = path_ls[0]
                real_path = os.path.join(_target_path, app_name)
                test_path_cmd_str = f"(test -d {_target_path} || mkdir -p {_target_path}) && " \
                                    f"tar -xmf {package_path} -C {_target_path} && mv {real_path} {target_path}/"
            is_success, message = salt_client.cmd(
                target=target_ip,
                command=test_path_cmd_str,
                timeout=self.timeout)
            if not is_success:
                raise Exception(message)

        except Exception as err:
            logger.error(f"Unzip Failed -> [{service_name}]: {err}")
            detail_obj.unzip_flag = 3
            detail_obj.unzip_msg += f"{self.now_time()} {service_name} " \
                                    f"解压服务包失败: {err}\n"
            detail_obj.install_step_status = DetailInstallHistory.INSTALL_STATUS_FAILED
            detail_obj.save()
            detail_obj.service.service_status = Service.SERVICE_STATUS_INSTALL_FAILED
            detail_obj.service.save()
            # 创建历史记录
            self.create_history(detail_obj, is_success=False)
            return False, err
        # 解压成功
        logger.info(
            f"Unzip Success -> [{service_name}] package [{package_name}]")
        detail_obj.unzip_flag = 2
        detail_obj.unzip_msg += f"{self.now_time()} {service_name} 成功解压服务包\n"
        detail_obj.save()
        return True, "Unzip Success"

    def install(self, detail_obj):
        """ 安装服务 """
        # 获取安装使用参数
        salt_client = SaltClient()
        target_ip = detail_obj.service.ip
        service_name = detail_obj.service.service_instance_name
        # edit by jon.liu service_controllers 为json字段,无需json.loads
        service_controllers_dict = detail_obj.service.service_controllers

        # 更新状态为 '安装中',记录日志
        logger.info(f"Install Begin -> [{service_name}]")
        detail_obj.install_flag = 1
        detail_obj.install_msg += f"{self.now_time()} {service_name} 开始安装服务\n"
        detail_obj.save()

        try:
            # 获取服务安装脚本绝对路径
            install_script_path = service_controllers_dict.get("install", "")
            if install_script_path == "":
                raise Exception("未找到安装脚本路径")

            # 获取 json 文件路径
            target_host = Host.objects.filter(ip=target_ip).first()
            assert target_host is not None
            json_path = os.path.join(
                target_host.data_folder, "omp_packages",
                f"{detail_obj.main_install_history.operation_uuid}.json")

            cmd_str = f"python {install_script_path} --local_ip {target_ip} --data_json {json_path}"

            # 执行安装
            is_success, message = salt_client.cmd(
                target=target_ip,
                command=cmd_str,
                timeout=self.timeout)
            if not is_success:
                raise Exception(message)
            # 执行成功且 message 有值,则补充至服务日志中
            if is_success and bool(message):
                detail_obj.install_msg += f"{self.now_time()} 安装脚本执行成功,脚本输出如下:\n" \
                                          f"{message}\n"
                detail_obj.save()
        except Exception as err:
            logger.error(f"Install Failed -> [{service_name}]: {err}")
            detail_obj.install_flag = 3
            detail_obj.install_msg += f"{self.now_time()} {service_name} " \
                                      f"安装服务失败: {err}\n"
            detail_obj.install_step_status = DetailInstallHistory.INSTALL_STATUS_FAILED
            detail_obj.save()
            detail_obj.service.service_status = Service.SERVICE_STATUS_INSTALL_FAILED
            detail_obj.service.save()
            # 创建历史记录
            self.create_history(detail_obj, is_success=False)
            return False, err
        # 安装成功
        logger.info(f"Install Success -> [{service_name}]")
        detail_obj.install_flag = 2
        detail_obj.install_msg += f"{self.now_time()} {service_name} 成功安装服务\n"
        detail_obj.save()
        return True, "Install Success"

    def init(self, detail_obj):
        """ 初始化服务 """
        # 获取初始化使用参数
        salt_client = SaltClient()
        target_ip = detail_obj.service.ip
        service_name = detail_obj.service.service_instance_name
        service_controllers_dict = detail_obj.service.service_controllers

        # 更新状态为 '初始化中',记录日志
        logger.info(f"Init Begin -> [{service_name}]")
        detail_obj.init_flag = 1
        detail_obj.init_msg += f"{self.now_time()} {service_name} 开始初始化服务\n"
        detail_obj.save()

        try:
            # 获取服务初始化脚本绝对路径
            init_script_path = service_controllers_dict.get("init", "")
            if init_script_path == "":
                logger.info(f"Init Un Do -> [{service_name}]")
                detail_obj.init_flag = 2
                detail_obj.init_msg += f"{self.now_time()} {service_name} 无需执行初始化\n"
                # 完成安装流程,更新状态为 '安装成功'
                detail_obj.install_step_status = \
                    DetailInstallHistory.INSTALL_STATUS_SUCCESS
                detail_obj.save()
                # 创建历史记录
                self.create_history(detail_obj, is_success=True)
                return True, "Init Un Do"

            # 获取 json 文件路径
            target_host = Host.objects.filter(ip=target_ip).first()
            assert target_host is not None
            json_path = os.path.join(
                target_host.data_folder, "omp_packages",
                f"{detail_obj.main_install_history.operation_uuid}.json")

            cmd_str = f"python {init_script_path} --local_ip {target_ip} " \
                      f"--data_json {json_path}"
            # 执行初始化
            is_success, message = salt_client.cmd(
                target=target_ip,
                command=cmd_str,
                timeout=self.timeout)
            if not is_success:
                raise Exception(message)
            # 执行成功且 message 有值,则补充至服务日志中
            if is_success and bool(message):
                detail_obj.install_msg += \
                    f"{self.now_time()} 初始化脚本执行成功,脚本输出如下:\n" \
                    f"{message}\n"
                detail_obj.save()
        except Exception as err:
            logger.error(f"Init Failed -> [{service_name}]: {err}")
            detail_obj.init_flag = 3
            detail_obj.init_msg += f"{self.now_time()} {service_name} " \
                                   f"初始化服务失败: {err}\n"
            # 更新安装流程状态为 '失败',服务状态为 '安装失败'
            detail_obj.install_step_status = \
                DetailInstallHistory.INSTALL_STATUS_FAILED
            detail_obj.save()
            detail_obj.service.service_status = \
                Service.SERVICE_STATUS_INSTALL_FAILED
            detail_obj.service.save()
            # 创建历史记录
            self.create_history(detail_obj, is_success=False)
            return False, err
        # 安装成功
        logger.info(f"Init Success -> [{service_name}]")
        detail_obj.init_flag = 2
        detail_obj.init_msg += f"{self.now_time()} {service_name} 成功初始化服务\n"
        # 完成安装流程,更新状态为 '安装成功'
        detail_obj.install_step_status = \
            DetailInstallHistory.INSTALL_STATUS_SUCCESS
        detail_obj.save()
        # 创建历史记录
        self.create_history(detail_obj, is_success=True)
        return True, "Init Success"

    def start(self, detail_obj):
        """ 启动服务 """
        # 获取启动使用参数
        salt_client = SaltClient()
        target_ip = detail_obj.service.ip
        service_name = detail_obj.service.service_instance_name
        service_controllers_dict = detail_obj.service.service_controllers

        # 更新状态为 '启动中',记录日志
        logger.info(f"Start Begin -> [{service_name}]")
        detail_obj.start_flag = 1
        detail_obj.start_msg += f"{self.now_time()} {service_name} 开始启动服务\n"
        detail_obj.save()

        try:
            # 获取服务启动脚本绝对路径
            start_script_path = service_controllers_dict.get("start", "")
            if start_script_path == "":
                logger.info(f"Start Un Do -> [{service_name}]")
                detail_obj.start_flag = 2
                detail_obj.start_msg += f"{self.now_time()} {service_name} 无需执行启动\n"
                # 服务状态更新为 '正常'
                detail_obj.service.service_status = \
                    Service.SERVICE_STATUS_NORMAL
                detail_obj.service.save()
                detail_obj.save()
                return True, "Start Un Do"
            if "start" not in start_script_path:
                start_script_path += " start"
            cmd_str = f"bash {start_script_path}"

            # 执行启动
            is_success, message = salt_client.cmd(
                target=target_ip,
                command=cmd_str,
                timeout=self.timeout)
            if not is_success:
                raise Exception(message)
            result_str = message.upper()
            if "FAILED" in result_str or \
                    "NO RUNNING" in result_str or \
                    "NOT RUNNING" in result_str:
                raise Exception(message)
            # 执行成功且 message 有值,则补充至服务日志中
            if is_success and bool(message):
                detail_obj.install_msg += \
                    f"{self.now_time()} 启动脚本执行成功,脚本输出如下:\n" \
                    f"{message}\n"
                detail_obj.save()
        except Exception as err:
            logger.error(f"Start Failed -> [{service_name}]: {err}")
            detail_obj.start_flag = 3
            detail_obj.start_msg += f"{self.now_time()} {service_name} " \
                                    f"启动服务失败: {err}\n"
            detail_obj.save()
            # 服务状态更新为 '停止'
            detail_obj.service.service_status = \
                Service.SERVICE_STATUS_STOP
            detail_obj.service.save()
            return False, err
        # 安装成功
        logger.info(f"Start Success -> [{service_name}]")
        detail_obj.start_flag = 2
        detail_obj.start_msg += f"{self.now_time()} {service_name} 成功启动服务\n"
        detail_obj.save()
        # 服务状态更新为 '正常'
        detail_obj.service.service_status = \
            Service.SERVICE_STATUS_NORMAL
        detail_obj.service.save()
        return True, "Start Success"

    @staticmethod
    def _is_base_env(detail_obj):
        """ 是否为依赖项,优先执行 """
        is_base_env = False
        try:
            base_env = detail_obj.service.service.extend_fields.get(
                "base_env", "")
            if isinstance(base_env, str):
                base_env = base_env.lower()
            if base_env in (True, "true"):
                is_base_env = True
        except Exception:
            pass
        return is_base_env

    @staticmethod
    def _is_dependency(detail_obj):
        """ 是否为依赖项,优先执行 """
        return False

    def main(self):
        """ 主函数 """
        logger.info(f"Main Install Begin, id[{self.main_id}]")
        # 获取主表对象,更新状态为 '安装中'
        main_obj = MainInstallHistory.objects.filter(
            id=self.main_id).first()
        assert main_obj is not None
        main_obj.install_status = \
            MainInstallHistory.INSTALL_STATUS_INSTALLING
        main_obj.save()

        # 获取所有安装细节表
        queryset = DetailInstallHistory.objects.select_related(
            "service", "service__service", "service__service__app_package"
        ).filter(main_install_history_id=self.main_id)
        assert queryset.exists()

        # 所有子流程状态更新为 '安装中'
        queryset.update(
            install_step_status=DetailInstallHistory.INSTALL_STATUS_INSTALLING)

        # 区分服务列表切分
        base_env_ls = []
        dependency_ls = []
        no_dependency_ls = []
        for detail_obj in queryset:
            if self._is_base_env(detail_obj):
                base_env_ls.append(detail_obj)
            elif self._is_dependency(detail_obj):
                dependency_ls.append(detail_obj)
            else:
                no_dependency_ls.append(detail_obj)
        logger.info(f"基础环境列表 [base_env_ls] -- {base_env_ls}")
        logger.info(f"含依赖列表 [dependency_ls] -- {dependency_ls}")
        logger.info(f"非依赖列表 [no_dependency_ls] -- {no_dependency_ls}")
        # TODO 含依赖项列表 -> 安装顺序排序?

        # 先执行 base_env 基础环境列表安装流程
        with ThreadPoolExecutor(THREAD_POOL_MAX_WORKERS) as executor:
            logger.info("Begin base_env install")
            for action in self.ACTION_LS:
                # ---- 基础环境列表并发 ----
                if self.is_error:
                    break
                _future_list_env = []
                for detail_obj in base_env_ls:
                    future_obj = executor.submit(
                        getattr(self, action), detail_obj)
                    _future_list_env.append(future_obj)
                for future in as_completed(_future_list_env):
                    is_success, message = future.result()
                    if not is_success:
                        self.is_error = True
                        break
            logger.info("End base_env install")

        with ThreadPoolExecutor(THREAD_POOL_MAX_WORKERS) as executor:
            # 轮询流程列表,进行安装
            logger.info("Begin else install")
            for action in self.ACTION_LS:
                logger.info(f"Enter [{action}]")
                # ---- 含依赖项列表轮询 ----
                if self.is_error:
                    break
                for detail_obj in dependency_ls:
                    is_success, message = getattr(self, action)(detail_obj)
                    if not is_success:
                        self.is_error = True
                        break
                # ---- 非依赖项列表并发 ----
                if self.is_error:
                    break
                _future_list = []
                for detail_obj in no_dependency_ls:
                    future_obj = executor.submit(
                        getattr(self, action), detail_obj)
                    _future_list.append(future_obj)
                for future in as_completed(_future_list):
                    is_success, message = future.result()
                    if not is_success:
                        self.is_error = True
                        break
            logger.info("End else install")

        if self.is_error:
            # 步骤失败,主流程失败
            main_obj.install_status = \
                MainInstallHistory.INSTALL_STATUS_FAILED
            main_obj.save()
            # 状态为 '待安装'/'安装中' 的记录,则记为 '失败'
            queryset.filter(install_step_status__in=(
                DetailInstallHistory.INSTALL_STATUS_READY,
                DetailInstallHistory.INSTALL_STATUS_INSTALLING
            )).update(install_step_status=DetailInstallHistory.INSTALL_STATUS_FAILED)
            logger.info(f"Main Install Failed, id[{self.main_id}]")
            return self.is_error

        # 流程执行完整,主流程成功
        main_obj.install_status = \
            MainInstallHistory.INSTALL_STATUS_SUCCESS
        main_obj.save()
        logger.info(f"Main Install Success, id[{self.main_id}]")
        return self.is_error


================================================
FILE: omp_server/app_store/install_utils.py
================================================
# -*- coding: utf-8 -*-
# Project: install_utils
# Author: jon.liu@yunzhihui.com
# Create time: 2021-10-24 14:11
# IDE: PyCharm
# Version: 1.0
# Introduction:

"""
安装过程中页面显示数据解析工具
"""

import os
import json
import uuid
from copy import deepcopy
from concurrent.futures import ThreadPoolExecutor

from django.db import transaction

from omp_server.settings import PROJECT_DIR
from db_models.models import (
    Env,
    Host,
    ApplicationHub,
    ProductHub,
    Product,
    Service,
    ClusterInfo,
    ServiceConnectInfo,
    MainInstallHistory,
    DetailInstallHistory
)
from app_store.tasks import install_service
from utils.common.exceptions import GeneralError
# from utils.plugin import public_utils
from utils.plugin.salt_client import SaltClient

DIR_KEY = "{data_path}"


def make_lst_unique(lst, 
Download .txt
gitextract_kwjdxdir/

├── .gitignore
├── .pre-commit-config.yaml
├── LICENSE
├── README.md
├── UpdateLog.md
├── component/
│   ├── .gitkeep
│   ├── alertmanager/
│   │   └── .gitkeep
│   ├── grafana/
│   │   └── .gitkeep
│   ├── loki/
│   │   └── .gitkeep
│   └── prometheus/
│       └── .gitkeep
├── config/
│   ├── omp.yaml
│   ├── private_key.pem
│   ├── product.yaml
│   └── salt/
│       ├── master
│       ├── minion
│       ├── minion.d/
│       │   └── _schedule.conf
│       └── minion.template
├── data/
│   ├── .gitkeep
│   └── inspection_file/
│       └── .gitkeep
├── doc/
│   ├── app_publish.md
│   └── changelogs.md
├── logs/
│   └── .gitkeep
├── omp_server/
│   ├── app_store/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── app_store_filters.py
│   │   ├── app_store_serializers.py
│   │   ├── apps.py
│   │   ├── cmd_install_utils.py
│   │   ├── deploy_mode_utils/
│   │   │   ├── __init__.py
│   │   │   ├── base.py
│   │   │   ├── even_num.py
│   │   │   ├── mysql.py
│   │   │   ├── normal.py
│   │   │   ├── odd_num.py
│   │   │   ├── rocketmq.py
│   │   │   └── tengine.py
│   │   ├── deploy_role_utils/
│   │   │   ├── __init__.py
│   │   │   ├── hadoop.py
│   │   │   ├── mysql.py
│   │   │   └── redis.py
│   │   ├── high_availability_utils/
│   │   │   ├── __init__.py
│   │   │   └── hadoop.py
│   │   ├── install_exec.py
│   │   ├── install_executor.py
│   │   ├── install_utils.py
│   │   ├── new_install_serializers.py
│   │   ├── new_install_utils.py
│   │   ├── new_install_view.py
│   │   ├── post_install_utils/
│   │   │   ├── __init__.py
│   │   │   ├── base.py
│   │   │   ├── nacos.py
│   │   │   └── tengine.py
│   │   ├── service_splitting.py
│   │   ├── tasks.py
│   │   ├── tmp_exec_back_task.py
│   │   ├── upload_task.py
│   │   ├── urls.py
│   │   ├── views.py
│   │   └── views_for_install.py
│   ├── backups/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── backup_service.py
│   │   ├── backups_serializers.py
│   │   ├── backups_utils.py
│   │   ├── migrations/
│   │   │   └── __init__.py
│   │   ├── tasks.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── db_models/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── migrations/
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_auto_20211202_1830.py
│   │   │   ├── 0003_host_init_status.py
│   │   │   ├── 0004_auto_20211203_1617.py
│   │   │   ├── 0005_auto_20211206_1723.py
│   │   │   ├── 0005_update_init_status.py
│   │   │   ├── 0006_merge_20211206_1833.py
│   │   │   ├── 0007_deploymentplan.py
│   │   │   ├── 0008_service_vip.py
│   │   │   ├── 0009_auto_20211228_1603.py
│   │   │   ├── 0010_auto_20220114_1830.py
│   │   │   ├── 0010_backuphistory_backupsetting.py
│   │   │   ├── 0011_auto_20220112_1607.py
│   │   │   ├── 0012_auto_20220112_1653.py
│   │   │   ├── 0013_merge_20220114_1838.py
│   │   │   ├── 0014_auto_20220121_1616.py
│   │   │   ├── 0015_executionrecord.py
│   │   │   ├── 0016_auto_20220125_1800.py
│   │   │   ├── 0017_selfhealinghistory_selfhealingsetting.py
│   │   │   ├── 0018_userloginlog_request_result.py
│   │   │   ├── 0019_toolexecutedetailhistory_toolexecutemainhistory_toolinfo_uploadfilehistory.py
│   │   │   ├── 0020_init_tools.py
│   │   │   ├── 0021_customscript.py
│   │   │   ├── 0022_alertrule_rule.py
│   │   │   ├── 0023_auto_20220225_1747.py
│   │   │   ├── 0024_auto_20220226_1300.py
│   │   │   ├── 0025_alertrule_forbidden.py
│   │   │   ├── 0026_alertrule_hash_data.py
│   │   │   ├── 0026_auto_20220303_1527.py
│   │   │   ├── 0027_merge_20220304_2000.py
│   │   │   ├── 0028_auto_20220304_2001.py
│   │   │   ├── 0029_auto_20230110_1739.py
│   │   │   ├── 0030_auto_20230711_1739.py
│   │   │   ├── 0031_auto_20230921_1128.py
│   │   │   └── __init__.py
│   │   ├── mixins.py
│   │   ├── models/
│   │   │   ├── __init__.py
│   │   │   ├── backup.py
│   │   │   ├── custom_metric.py
│   │   │   ├── email.py
│   │   │   ├── env.py
│   │   │   ├── execution.py
│   │   │   ├── host.py
│   │   │   ├── inspection.py
│   │   │   ├── install.py
│   │   │   ├── monitor.py
│   │   │   ├── product.py
│   │   │   ├── self_heal.py
│   │   │   ├── service.py
│   │   │   ├── threshold.py
│   │   │   ├── tool.py
│   │   │   ├── upgrade.py
│   │   │   ├── upload.py
│   │   │   └── user.py
│   │   ├── receivers/
│   │   │   ├── __init__.py
│   │   │   ├── execution_record.py
│   │   │   └── service.py
│   │   └── signals/
│   │       └── __init__.py
│   ├── dev_code.md
│   ├── dev_requirement.txt
│   ├── hosts/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── hosts_filters.py
│   │   ├── hosts_serializers.py
│   │   ├── tasks.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── inspection/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── filters.py
│   │   ├── get_prometheus_risk_data.py
│   │   ├── get_service_topology.py
│   │   ├── inspection_utils.py
│   │   ├── joint_json_report.py
│   │   ├── serializers.py
│   │   ├── tasks.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── manage.py
│   ├── omp_server/
│   │   ├── __init__.py
│   │   ├── asgi.py
│   │   ├── celery.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── promemonitor/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── alert_util.py
│   │   ├── alertmanager.py
│   │   ├── apps.py
│   │   ├── custom_script_serializers.py
│   │   ├── custom_script_views.py
│   │   ├── grafana_url.py
│   │   ├── grafana_views.py
│   │   ├── promemonitor_filters.py
│   │   ├── promemonitor_serializers.py
│   │   ├── prometheus.py
│   │   ├── prometheus_utils.py
│   │   ├── tasks.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── service_upgrade/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── filters.py
│   │   ├── handler/
│   │   │   ├── __init__.py
│   │   │   ├── base.py
│   │   │   ├── rollback_handler.py
│   │   │   └── upgrade_handler.py
│   │   ├── serializers.py
│   │   ├── tasks.py
│   │   ├── update_data_json.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── services/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── app_check/
│   │   │   ├── __init__.py
│   │   │   ├── conf_check.py
│   │   │   └── manage_ser_exec.py
│   │   ├── apps.py
│   │   ├── permission.py
│   │   ├── self_heal_filter.py
│   │   ├── self_heal_serializers.py
│   │   ├── self_heal_util.py
│   │   ├── self_heal_view.py
│   │   ├── self_healing.py
│   │   ├── services_filters.py
│   │   ├── services_serializers.py
│   │   ├── tasks.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── tests/
│   │   ├── __init__.py
│   │   ├── base.py
│   │   ├── mixin.py
│   │   ├── test_app_store/
│   │   │   ├── __init__.py
│   │   │   ├── install_data_source.py
│   │   │   ├── make_install_fake_data.py
│   │   │   ├── test_app_check.py
│   │   │   ├── test_app_store.py
│   │   │   ├── test_app_store_install.py
│   │   │   ├── test_app_store_upload.py
│   │   │   ├── test_execute_package_scan.py
│   │   │   ├── test_get_application_template.py
│   │   │   ├── test_install_executor.py
│   │   │   ├── test_new_install.py
│   │   │   └── test_upload_package.py
│   │   ├── test_hosts/
│   │   │   ├── __init__.py
│   │   │   ├── test_celery_tasks.py
│   │   │   └── test_hosts.py
│   │   ├── test_inspection/
│   │   │   ├── __init__.py
│   │   │   ├── inspection_mixin.py
│   │   │   ├── test_crontab.py
│   │   │   ├── test_history.py
│   │   │   ├── test_inspection_email.py
│   │   │   └── test_report.py
│   │   ├── test_promemonitor/
│   │   │   ├── __init__.py
│   │   │   ├── test_alert.py
│   │   │   ├── test_alertmanager.py
│   │   │   ├── test_celery_tasks.py
│   │   │   ├── test_email_config.py
│   │   │   ├── test_global_maintain.py
│   │   │   ├── test_grafana_url.py
│   │   │   ├── test_grafana_views.py
│   │   │   ├── test_instance_name_list.py
│   │   │   ├── test_instrument_panel.py
│   │   │   ├── test_monitor_agent_restart.py
│   │   │   ├── test_promemonitor_url.py
│   │   │   ├── test_prometheus.py
│   │   │   ├── test_prometheus_utils.py
│   │   │   ├── test_receive_alert.py
│   │   │   └── test_threshold_rw.py
│   │   ├── test_services/
│   │   │   ├── __init__.py
│   │   │   ├── test_service_actions.py
│   │   │   └── test_services.py
│   │   ├── test_users/
│   │   │   ├── __init__.py
│   │   │   ├── test_login.py
│   │   │   └── test_users.py
│   │   └── test_utils/
│   │       ├── __init__.py
│   │       ├── test_agent_util.py
│   │       ├── test_crontab_utils.py
│   │       ├── test_crypto.py
│   │       ├── test_monitor_agent.py
│   │       ├── test_public_utils.py
│   │       ├── test_salt_client.py
│   │       └── test_ssh.py
│   ├── tool/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── find_tools.py
│   │   ├── serializers.py
│   │   ├── tasks.py
│   │   ├── tests.py
│   │   ├── tool_filters.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── users/
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── urls.py
│   │   ├── users_filters.py
│   │   ├── users_serializers.py
│   │   └── views.py
│   └── utils/
│       ├── __init__.py
│       ├── common/
│       │   ├── __init__.py
│       │   ├── exceptions.py
│       │   ├── paginations.py
│       │   ├── serializers.py
│       │   ├── urls.py
│       │   ├── validators.py
│       │   └── views.py
│       ├── exception_handler.py
│       ├── middleware_handler.py
│       ├── parse_config.py
│       ├── plugin/
│       │   ├── __init__.py
│       │   ├── agent_util.py
│       │   ├── captcha/
│       │   │   ├── __init__.py
│       │   │   └── captcha.py
│       │   ├── crontab_utils.py
│       │   ├── crypto.py
│       │   ├── install_ntpdate.py
│       │   ├── monitor_agent.py
│       │   ├── public_utils.py
│       │   ├── salt_client.py
│       │   ├── send_email.py
│       │   ├── ssh.py
│       │   └── synch_grafana.py
│       ├── prometheus/
│       │   ├── __init__.py
│       │   ├── create_html_tar.py
│       │   ├── prometheus.py
│       │   ├── target_host.py
│       │   ├── target_service.py
│       │   ├── target_service_arangodb.py
│       │   ├── target_service_beanstalk.py
│       │   ├── target_service_clickhouse.py
│       │   ├── target_service_elasticsearch.py
│       │   ├── target_service_flink.py
│       │   ├── target_service_func.py
│       │   ├── target_service_gotty.py
│       │   ├── target_service_grafana.py
│       │   ├── target_service_hadoop.py
│       │   ├── target_service_httpd.py
│       │   ├── target_service_ignite.py
│       │   ├── target_service_jvm_base.py
│       │   ├── target_service_kafka.py
│       │   ├── target_service_mysql.py
│       │   ├── target_service_nacos.py
│       │   ├── target_service_ntpd.py
│       │   ├── target_service_postgresql.py
│       │   ├── target_service_prometheus.py
│       │   ├── target_service_redis.py
│       │   ├── target_service_rocketmq.py
│       │   ├── target_service_tengine.py
│       │   ├── target_service_zookeeper.py
│       │   ├── thread.py
│       │   ├── update_threshold.py
│       │   └── utils.py
│       └── response_handler.py
├── omp_web/
│   ├── README.md
│   ├── config-overrides.js
│   ├── package.json
│   ├── public/
│   │   ├── index.html
│   │   └── pubKey.json
│   ├── src/
│   │   ├── App.js
│   │   ├── components/
│   │   │   ├── CustomBreadcrumb/
│   │   │   │   ├── index.js
│   │   │   │   ├── index.module.less
│   │   │   │   └── store/
│   │   │   │       ├── actionsCreators.js
│   │   │   │       ├── constants.js
│   │   │   │       ├── index.js
│   │   │   │       └── reduer.js
│   │   │   ├── OmpButton/
│   │   │   │   └── index.js
│   │   │   ├── OmpCollapseWrapper/
│   │   │   │   ├── index.js
│   │   │   │   ├── index.module.less
│   │   │   │   └── indexOld.js
│   │   │   ├── OmpContentNav/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── OmpContentWrapper/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── OmpDatePicker/
│   │   │   │   └── index.js
│   │   │   ├── OmpDrawer/
│   │   │   │   └── index.js
│   │   │   ├── OmpIframe/
│   │   │   │   └── index.js
│   │   │   ├── OmpMaintenanceModal/
│   │   │   │   └── index.js
│   │   │   ├── OmpMessageModal/
│   │   │   │   └── index.js
│   │   │   ├── OmpModal/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── OmpOperationWrapper/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── OmpProgress/
│   │   │   │   └── index.js
│   │   │   ├── OmpSelect/
│   │   │   │   └── index.js
│   │   │   ├── OmpStateBlock/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── OmpTable/
│   │   │   │   ├── components/
│   │   │   │   │   └── OmpTableFilter.js
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── OmpToolTip/
│   │   │   │   └── index.js
│   │   │   └── index.js
│   │   ├── config/
│   │   │   ├── requestApi.js
│   │   │   └── router.config.js
│   │   ├── index.js
│   │   ├── layouts/
│   │   │   ├── container/
│   │   │   │   └── container.js
│   │   │   ├── index.js
│   │   │   ├── index.module.less
│   │   │   ├── indexOld.js
│   │   │   └── store/
│   │   │       ├── actionsCreators.js
│   │   │       ├── constants.js
│   │   │       ├── index.js
│   │   │       └── reduer.js
│   │   ├── pages/
│   │   │   ├── AlarmLog/
│   │   │   │   ├── config/
│   │   │   │   │   └── columns.js
│   │   │   │   └── index.js
│   │   │   ├── AppStore/
│   │   │   │   ├── config/
│   │   │   │   │   ├── ApplicationInstallation.js
│   │   │   │   │   ├── BatchInstallationModal.js
│   │   │   │   │   ├── ComponentInstallation.js
│   │   │   │   │   ├── DeleteServerModal.js
│   │   │   │   │   ├── GetService.js
│   │   │   │   │   ├── GetServiceModal.js
│   │   │   │   │   ├── Installation/
│   │   │   │   │   │   ├── component/
│   │   │   │   │   │   │   ├── BasicInfoItem/
│   │   │   │   │   │   │   │   └── index.js
│   │   │   │   │   │   │   ├── DependentinfoItem/
│   │   │   │   │   │   │   │   ├── component/
│   │   │   │   │   │   │   │   │   ├── DeployInstanceRow.js
│   │   │   │   │   │   │   │   │   ├── DeployNumRow.js
│   │   │   │   │   │   │   │   │   ├── DeployRow.js
│   │   │   │   │   │   │   │   │   ├── JdkRow.js
│   │   │   │   │   │   │   │   │   ├── RenderArr.js
│   │   │   │   │   │   │   │   │   └── RenderNum.js
│   │   │   │   │   │   │   │   └── index.js
│   │   │   │   │   │   │   ├── InstallInfoItem/
│   │   │   │   │   │   │   │   ├── component/
│   │   │   │   │   │   │   │   │   └── InstallDetail.js
│   │   │   │   │   │   │   │   └── index.js
│   │   │   │   │   │   │   ├── ServiceConfigItem/
│   │   │   │   │   │   │   │   └── index.js
│   │   │   │   │   │   │   ├── ServiceDistributionItem/
│   │   │   │   │   │   │   │   ├── component/
│   │   │   │   │   │   │   │   │   └── HasInstallService.js
│   │   │   │   │   │   │   │   └── index.js
│   │   │   │   │   │   │   └── index.module.less
│   │   │   │   │   │   ├── index.js
│   │   │   │   │   │   ├── index.module.less
│   │   │   │   │   │   ├── steps/
│   │   │   │   │   │   │   ├── Step1.js
│   │   │   │   │   │   │   ├── Step2.js
│   │   │   │   │   │   │   ├── Step3.js
│   │   │   │   │   │   │   └── Step4.js
│   │   │   │   │   │   └── store/
│   │   │   │   │   │       ├── actionsCreators.js
│   │   │   │   │   │       ├── constants.js
│   │   │   │   │   │       ├── index.js
│   │   │   │   │   │       └── reduer.js
│   │   │   │   │   ├── ReleaseModal.js
│   │   │   │   │   ├── Rollback/
│   │   │   │   │   │   ├── content/
│   │   │   │   │   │   │   ├── component/
│   │   │   │   │   │   │   │   ├── RollbackDetail.js
│   │   │   │   │   │   │   │   └── RollbackInfoItem.js
│   │   │   │   │   │   │   └── index.js
│   │   │   │   │   │   ├── index.js
│   │   │   │   │   │   └── index.module.less
│   │   │   │   │   ├── ScanServerModal.js
│   │   │   │   │   ├── ServiceRollbackModal.js
│   │   │   │   │   ├── ServiceUpgradeModal.js
│   │   │   │   │   ├── Upgrade/
│   │   │   │   │   │   ├── content/
│   │   │   │   │   │   │   ├── component/
│   │   │   │   │   │   │   │   ├── UpgradeDetail.js
│   │   │   │   │   │   │   │   └── UpgradeInfoItem.js
│   │   │   │   │   │   │   └── index.js
│   │   │   │   │   │   ├── index.js
│   │   │   │   │   │   └── index.module.less
│   │   │   │   │   ├── card.js
│   │   │   │   │   ├── component/
│   │   │   │   │   │   └── RenderComDependence.js
│   │   │   │   │   ├── detail.js
│   │   │   │   │   ├── img.js
│   │   │   │   │   └── index.module.less
│   │   │   │   ├── index.js
│   │   │   │   ├── index.module.less
│   │   │   │   └── store/
│   │   │   │       ├── actionsCreators.js
│   │   │   │       ├── constants.js
│   │   │   │       ├── index.js
│   │   │   │       └── reduer.js
│   │   │   ├── BackupRecords/
│   │   │   │   ├── config/
│   │   │   │   │   └── columns.js
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── BackupStrategy/
│   │   │   │   ├── CustomModal.js
│   │   │   │   ├── StrategyModal.js
│   │   │   │   ├── config/
│   │   │   │   │   └── columns.js
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── DeploymentPlan/
│   │   │   │   ├── config/
│   │   │   │   │   ├── columns.js
│   │   │   │   │   └── models.js
│   │   │   │   └── index.js
│   │   │   ├── EmailSettings/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── ExceptionList/
│   │   │   │   ├── config/
│   │   │   │   │   └── columns.js
│   │   │   │   └── index.js
│   │   │   ├── HomePage/
│   │   │   │   ├── index.js
│   │   │   │   ├── index.module.less
│   │   │   │   └── warningList.js
│   │   │   ├── InstallationRecord/
│   │   │   │   ├── config/
│   │   │   │   │   └── ServiceUpgradeModal.js
│   │   │   │   ├── index.js
│   │   │   │   ├── indexOld.js
│   │   │   │   └── tabs/
│   │   │   │       ├── installation.js
│   │   │   │       ├── rollback.js
│   │   │   │       └── upgrade.js
│   │   │   ├── Login/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── LoginLog/
│   │   │   │   └── index.js
│   │   │   ├── MachineManagement/
│   │   │   │   ├── config/
│   │   │   │   │   ├── columns.js
│   │   │   │   │   └── modals.js
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── MonitoringSettings/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── PatrolInspectionRecord/
│   │   │   │   ├── config/
│   │   │   │   │   ├── columns.js
│   │   │   │   │   ├── detail.js
│   │   │   │   │   └── index.css
│   │   │   │   └── index.js
│   │   │   ├── PatrolStrategy/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── RuleCenter/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── RuleExtend/
│   │   │   │   └── index.js
│   │   │   ├── RuleIndicator/
│   │   │   │   └── index.js
│   │   │   ├── SelfHealingRecord/
│   │   │   │   ├── config/
│   │   │   │   │   └── columns.js
│   │   │   │   └── index.js
│   │   │   ├── SelfHealingStrategy/
│   │   │   │   ├── StrategyModal.js
│   │   │   │   ├── config/
│   │   │   │   │   └── columns.js
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── ServiceManagement/
│   │   │   │   ├── config/
│   │   │   │   │   └── columns.js
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── SystemLog/
│   │   │   │   └── index.js
│   │   │   ├── SystemManagement/
│   │   │   │   ├── index.js
│   │   │   │   ├── index.module.less
│   │   │   │   └── store/
│   │   │   │       ├── actionsCreators.js
│   │   │   │       ├── constants.js
│   │   │   │       ├── index.js
│   │   │   │       └── reduer.js
│   │   │   ├── TaskRecord/
│   │   │   │   └── index.js
│   │   │   ├── ToolExecution/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── ToolExecutionResults/
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   ├── ToolManagement/
│   │   │   │   ├── config/
│   │   │   │   │   ├── card.js
│   │   │   │   │   └── index.module.less
│   │   │   │   ├── detail/
│   │   │   │   │   ├── Readme.js
│   │   │   │   │   ├── index.js
│   │   │   │   │   └── index.module.less
│   │   │   │   ├── index.js
│   │   │   │   └── index.module.less
│   │   │   └── UserManagement/
│   │   │       └── index.js
│   │   ├── react-app-env.d.ts
│   │   ├── router.js
│   │   ├── store_redux/
│   │   │   ├── reducer.js
│   │   │   └── reduxStore.js
│   │   └── utils/
│   │       ├── index.module.less
│   │       ├── request.js
│   │       └── utils.js
│   └── tsconfig.json
├── package_hub/
│   ├── .gitkeep
│   ├── _modules/
│   │   ├── __init__.py
│   │   ├── arangodb_check.py
│   │   ├── beanstalkd_check.py
│   │   ├── clickhouse_check.py
│   │   ├── elasticsearch_check.py
│   │   ├── flink_check.py
│   │   ├── get_agent_info.py
│   │   ├── gotty_check.py
│   │   ├── grafana_check.py
│   │   ├── hadoop_check.py
│   │   ├── host_check.py
│   │   ├── httpd_check.py
│   │   ├── ignite_check.py
│   │   ├── init_host.py
│   │   ├── inspection_common.py
│   │   ├── kafka_check.py
│   │   ├── minio_check.py
│   │   ├── mysql_bak.sh.tmp
│   │   ├── mysql_check.py
│   │   ├── nacos_check.py
│   │   ├── ntpd_check.py
│   │   ├── postgreSql_bak.sh.tmp
│   │   ├── postgresql_check.py
│   │   ├── prometheus_check.py
│   │   ├── rocketmq_check.py
│   │   ├── tengine_check.py
│   │   ├── tomcat_check.py
│   │   └── zookeeper_check.py
│   ├── back_end_verified/
│   │   └── .gitkeep
│   ├── custom_scripts/
│   │   ├── .gitkeep
│   │   └── template.py
│   ├── data_files/
│   │   └── .gitkeep
│   ├── front_end_verified/
│   │   └── .gitkeep
│   ├── grafana_dashboard_json/
│   │   ├──  21-rediscluster-xin-xi-mian-ban.json
│   │   ├── 1-zhu-ji-xin-xi-mian-ban.json
│   │   ├── 10-ignite-xin-xi-mian-ban.json
│   │   ├── 11-kafka-xin-xi-mian-ban.json
│   │   ├── 12-mysql-xin-xi-mian-ban.json
│   │   ├── 13-nacos-xin-xi-mian-ban.json
│   │   ├── 14-postgresql-xin-xi-mian-ban.json
│   │   ├── 15-redis-xin-xi-mian-ban.json
│   │   ├── 16-tengine-nginx-xin-xi-mian-ban.json
│   │   ├── 17-zookeeper-xin-xi-mian-ban.json
│   │   ├── 18-exporter-status.json
│   │   ├── 19-jvm-xin-xi-mian-ban.json
│   │   ├── 2-fu-wu-zhuang-tai-xin-xi-mian-ban.json
│   │   ├── 20-clickhousecluster-xin-xi-mian-ban.json
│   │   ├── 22-mysqlcluster-xin-xi-mian-ban.json
│   │   ├── 23-tenginecluster-nginx-xin-xi-mian-ban.json
│   │   ├── 24-victoriametrics-xin-xi-mian-ban.json
│   │   ├── 25-rocketmq-xin-xi-mian-ban.json
│   │   ├── 3-mian-ban-lie-biao.json
│   │   ├── 4-app-logs.json
│   │   ├── 5-arangodb-xin-xi-mian-ban.json
│   │   ├── 6-beanstalkdxin-xi-mian-ban.json
│   │   ├── 7-clickhouse-xin-xi-mian-ban.json
│   │   ├── 8-elasticsearch-xin-xi-mian-ban.json
│   │   └── 9-httpd-xin-xi-mian-ban.json
│   ├── openssl_upgrade/
│   │   └── upgrade_ssl.sh
│   ├── prometheus_rules_template/
│   │   ├── exporter_status_rule.yml
│   │   ├── node_data_rule.yml
│   │   ├── node_rule.yml
│   │   └── service_status_rule.yml
│   ├── reactor/
│   │   ├── auth.sls
│   │   ├── start.sls
│   │   └── stop.sls
│   ├── runners/
│   │   ├── agent_start.py
│   │   └── agent_stop.py
│   ├── template/
│   │   ├── app_publish_readme.md
│   │   ├── deployment.xlsx
│   │   ├── import_hosts_template.xlsx
│   │   ├── inspection_html/
│   │   │   ├── asset-manifest.json
│   │   │   ├── index.html
│   │   │   └── static/
│   │   │       ├── css/
│   │   │       │   ├── 2.8ca66de9.chunk.css
│   │   │       │   └── main.041ca26a.chunk.css
│   │   │       ├── js/
│   │   │       │   ├── 2.0ca9bd94.chunk.js
│   │   │       │   ├── 2.0ca9bd94.chunk.js.LICENSE.txt
│   │   │       │   ├── main.e4ade54a.chunk.js
│   │   │       │   └── runtime-main.da7bcbe2.js
│   │   │       └── media/
│   │   │           ├── index.02867153.less
│   │   │           ├── index.2041a1d4.less
│   │   │           ├── index.2f186d27.less
│   │   │           ├── index.32dc937e.less
│   │   │           ├── index.383af9c4.less
│   │   │           ├── index.51825487.less
│   │   │           ├── index.60c6e3ea.less
│   │   │           ├── index.67101e84.less
│   │   │           ├── index.68b48da1.less
│   │   │           ├── index.73987a8f.less
│   │   │           ├── index.8372475c.less
│   │   │           ├── index.85c775e4.less
│   │   │           ├── index.8c12967b.less
│   │   │           ├── index.976fe83e.less
│   │   │           ├── index.cae8fdaf.less
│   │   │           ├── index.d15ddbc9.less
│   │   │           ├── index.d61ddb9a.less
│   │   │           ├── index.e1e14bcc.less
│   │   │           ├── index.e90871b5.less
│   │   │           └── index.module.b57695f6.less
│   │   └── template.md
│   ├── tmp_end_verified/
│   │   └── .gitkeep
│   ├── tool/
│   │   ├── download_data/
│   │   │   └── .gitkeep
│   │   ├── folder/
│   │   │   └── .gitkeep
│   │   ├── tar/
│   │   │   └── .gitkeep
│   │   ├── upload_data/
│   │   │   └── .gitkeep
│   │   └── verify_tar/
│   │       └── .gitkeep
│   └── verified/
│       └── .gitkeep
├── salt/
│   ├── master
│   ├── minion
│   ├── minion.d/
│   │   └── _schedule.conf
│   └── minion.template
└── scripts/
    ├── cmd_manager
    ├── install.sh
    ├── omp
    ├── source/
    │   ├── __init__.py
    │   ├── add_readonly_user.py
    │   ├── cmd_install_entrance.py
    │   ├── cron
    │   ├── features.py
    │   ├── install_mysql_redis.py
    │   ├── install_or_update.py
    │   ├── omp_rollback.py
    │   ├── omp_salt_agent
    │   ├── omp_upgrade.py
    │   ├── repair_dirty_data.py
    │   ├── salt
    │   ├── salt_agent_manager
    │   ├── scan_tar_file.py
    │   ├── scan_tools.py
    │   ├── service_manager.py
    │   ├── tengine
    │   ├── uninstall_app_store.py
    │   ├── uninstall_services.py
    │   ├── update_conf.py
    │   ├── update_data.py
    │   ├── update_grafana.py
    │   ├── update_monitor_agent.py
    │   ├── upgrade_service.py
    │   ├── uwsgi
    │   └── worker
    └── uninstall.sh
Download .txt
Showing preview only (387K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (4568 symbols across 337 files)

FILE: omp_server/app_store/app_store_filters.py
  class LabelFilter (line 13) | class LabelFilter(FilterSet):
    class Meta (line 18) | class Meta:
  class ComponentFilter (line 23) | class ComponentFilter(FilterSet):
    class Meta (line 30) | class Meta:
  class ServiceFilter (line 35) | class ServiceFilter(FilterSet):
    class Meta (line 42) | class Meta:
  class UploadPackageHistoryFilter (line 47) | class UploadPackageHistoryFilter(FilterSet):
    class Meta (line 52) | class Meta:
  class PublishPackageHistoryFilter (line 57) | class PublishPackageHistoryFilter(FilterSet):
    class Meta (line 62) | class Meta:
  class ComponentEntranceFilter (line 67) | class ComponentEntranceFilter(FilterSet):
    class Meta (line 73) | class Meta:
  class ProductEntranceFilter (line 79) | class ProductEntranceFilter(FilterSet):
    class Meta (line 85) | class Meta:
  class InstallHistoryFilter (line 91) | class InstallHistoryFilter(FilterSet):
    class Meta (line 97) | class Meta:
  class ServiceInstallHistoryFilter (line 103) | class ServiceInstallHistoryFilter(FilterSet):
    class Meta (line 109) | class Meta:

FILE: omp_server/app_store/app_store_serializers.py
  class ComponentListSerializer (line 35) | class ComponentListSerializer(ModelSerializer):
    class Meta (line 39) | class Meta:
    method get_instance_number (line 45) | def get_instance_number(self, obj):
  class ServiceListSerializer (line 51) | class ServiceListSerializer(ModelSerializer):
    class Meta (line 55) | class Meta:
    method get_instance_number (line 61) | def get_instance_number(self, obj):
  class UploadPackageSerializer (line 68) | class UploadPackageSerializer(Serializer):
    method validate (line 92) | def validate(self, attrs):
    method create (line 107) | def create(self, validated_data):
  class RemovePackageSerializer (line 138) | class RemovePackageSerializer(Serializer):
    method validate (line 154) | def validate(self, attrs):
    method create (line 172) | def create(self, validated_data):
  class ApplicationDetailSerializer (line 180) | class ApplicationDetailSerializer(ModelSerializer):  # NOQA
    class Meta (line 187) | class Meta:
    method get_app_instances_info (line 194) | def get_app_instances_info(self, obj):  # NOQA
    method get_app_labels (line 210) | def get_app_labels(self, obj):  # NOQA
    method get_app_package_md5 (line 213) | def get_app_package_md5(self, obj):  # NOQA
    method get_app_operation_user (line 219) | def get_app_operation_user(self, obj):  # NOQA
  class ProductDetailSerializer (line 223) | class ProductDetailSerializer(ModelSerializer):  # NOQA
    class Meta (line 232) | class Meta:
    method get_pro_instances_info (line 240) | def get_pro_instances_info(self, obj):  # NOQA
    method get_pro_labels (line 258) | def get_pro_labels(self, obj):  # NOQA
    method get_pro_package_md5 (line 261) | def get_pro_package_md5(self, obj):  # NOQA
    method get_pro_operation_user (line 267) | def get_pro_operation_user(self, obj):  # NOQA
    method get_pro_services (line 274) | def get_pro_services(self, obj):  # NOQA
  class UploadPackageHistorySerializer (line 302) | class UploadPackageHistorySerializer(serializers.ModelSerializer):
    class Meta (line 305) | class Meta:
  class PublishPackageHistorySerializer (line 312) | class PublishPackageHistorySerializer(serializers.ModelSerializer):
    class Meta (line 315) | class Meta:
  class ExecuteLocalPackageScanSerializer (line 322) | class ExecuteLocalPackageScanSerializer(Serializer):
  class ComponentEntranceSerializer (line 327) | class ComponentEntranceSerializer(serializers.ModelSerializer):
    method get_app_port (line 337) | def get_app_port(self, obj):  # NOQA
    method get_app_dependence (line 341) | def get_app_dependence(self, obj):  # NOQA
    method get_app_install_args (line 345) | def get_app_install_args(self, obj):  # NOQA
    method get_deploy_mode (line 349) | def get_deploy_mode(self, obj):  # NOQA
    method get_process_continue (line 353) | def get_process_continue(self, obj):  # NOQA
    method get_process_message (line 357) | def get_process_message(self, obj):  # NOQA
    class Meta (line 360) | class Meta:
  class ProductEntranceSerializer (line 370) | class ProductEntranceSerializer(serializers.ModelSerializer):
    method get_pro_services (line 377) | def get_pro_services(self, obj):  # NOQA
    method get_pro_dependence (line 401) | def get_pro_dependence(self, obj):  # NOQA
    method get_dependence_services_info (line 407) | def get_dependence_services_info(self, obj):  # NOQA
    class Meta (line 422) | class Meta:
  class ExecuteInstallSerializer (line 431) | class ExecuteInstallSerializer(Serializer):
    method validate_use_exist_services (line 477) | def validate_use_exist_services(self, data):  # NOQA
    method validate_install_services (line 487) | def validate_install_services(self, data):  # NOQA
    method check_lst_valid (line 495) | def check_lst_valid(self, lst):  # NOQA
    method validate (line 508) | def validate(self, attrs):
  class InstallHistorySerializer (line 544) | class InstallHistorySerializer(ModelSerializer):
    method parse_single_obj (line 550) | def parse_single_obj(self, obj):  # NOQA
    method get_detail_lst (line 578) | def get_detail_lst(self, obj):  # NOQA
    class Meta (line 589) | class Meta:
  class ServiceInstallHistorySerializer (line 598) | class ServiceInstallHistorySerializer(ModelSerializer):
    method get_install_step_status (line 603) | def get_install_step_status(self, obj):
    method get_log (line 612) | def get_log(self, obj):
    class Meta (line 632) | class Meta:
  class DeploymentPlanValidateSerializer (line 640) | class DeploymentPlanValidateSerializer(Serializer):
    method validate (line 657) | def validate(self, attrs):
  class DeploymentImportSerializer (line 834) | class DeploymentImportSerializer(Serializer):
  class DeploymentPlanListSerializer (line 858) | class DeploymentPlanListSerializer(ModelSerializer):
    class Meta (line 861) | class Meta:
  class ExecutionRecordSerializer (line 867) | class ExecutionRecordSerializer(ModelSerializer):
    method get_can_rollback (line 872) | def get_can_rollback(self, obj):
    method get_duration (line 880) | def get_duration(self, obj):
    class Meta (line 885) | class Meta:
  class ProductCompositionSerializer (line 892) | class ProductCompositionSerializer(ModelSerializer):
    method get_pro_ser_others (line 905) | def get_pro_ser_others(self, obj, **kwargs):
    method validate_pro_services (line 930) | def validate_pro_services(self, pro_services):
    method validate (line 946) | def validate(self, attrs):
    class Meta (line 962) | class Meta:
  class DeleteComponentSerializer (line 967) | class DeleteComponentSerializer(ModelSerializer):
    class Meta (line 974) | class Meta:
    method get_name (line 979) | def get_name(self, obj):
    method get_versions (line 982) | def get_versions(self, obj):
  class DeleteProDuctSerializer (line 986) | class DeleteProDuctSerializer(ModelSerializer):
    class Meta (line 993) | class Meta:
    method get_name (line 998) | def get_name(self, obj):
    method get_versions (line 1001) | def get_versions(self, obj):

FILE: omp_server/app_store/apps.py
  class AppStoreConfig (line 4) | class AppStoreConfig(AppConfig):

FILE: omp_server/app_store/cmd_install_utils.py
  class ReadDeploymentExcel (line 14) | class ReadDeploymentExcel(object):
    method __init__ (line 17) | def __init__(self, excel_path):
    method _read (line 24) | def _read(start_row=1, keys=None, table=None):
    method read_host_info (line 67) | def read_host_info(self, table):
    method read_service_info (line 87) | def read_service_info(self, table):
    method read_excel (line 103) | def read_excel(self):

FILE: omp_server/app_store/deploy_mode_utils/base.py
  class BaseUtils (line 10) | class BaseUtils(object):
    method __init__ (line 13) | def __init__(self, host_num, high_availability):
    method get (line 23) | def get(self):
    method check (line 30) | def check(self, mode):

FILE: omp_server/app_store/deploy_mode_utils/even_num.py
  class EvenNumUtils (line 17) | class EvenNumUtils(BaseUtils):
    method get (line 20) | def get(self):
    method check (line 35) | def check(self, mode):

FILE: omp_server/app_store/deploy_mode_utils/mysql.py
  class MysqlUtils (line 16) | class MysqlUtils(BaseUtils):
    method get (line 19) | def get(self):
    method check (line 61) | def check(self, mode):

FILE: omp_server/app_store/deploy_mode_utils/normal.py
  class NormalUtils (line 17) | class NormalUtils(BaseUtils):
    method get (line 20) | def get(self):
    method check (line 35) | def check(self, mode):

FILE: omp_server/app_store/deploy_mode_utils/odd_num.py
  class OddNumUtils (line 17) | class OddNumUtils(BaseUtils):
    method get (line 20) | def get(self):
    method check (line 40) | def check(self, mode):

FILE: omp_server/app_store/deploy_mode_utils/rocketmq.py
  class RocketmqUtils (line 16) | class RocketmqUtils(BaseUtils):
    method get (line 19) | def get(self):
    method check (line 44) | def check(self, mode):

FILE: omp_server/app_store/deploy_mode_utils/tengine.py
  class TengineUtils (line 16) | class TengineUtils(BaseUtils):
    method get (line 19) | def get(self):
    method check (line 39) | def check(self, mode):

FILE: omp_server/app_store/deploy_role_utils/hadoop.py
  class Hadoop (line 14) | class Hadoop(object):
    method update_service (line 16) | def update_service(service_list):

FILE: omp_server/app_store/deploy_role_utils/mysql.py
  class Mysql (line 15) | class Mysql(object):
    method update_service (line 17) | def update_service(service_list):

FILE: omp_server/app_store/deploy_role_utils/redis.py
  class Redis (line 14) | class Redis(object):
    method update_service (line 16) | def update_service(service_list):

FILE: omp_server/app_store/high_availability_utils/hadoop.py
  class Hadoop (line 21) | class Hadoop(object):
    method __init__ (line 30) | def __init__(self, install_exec_obj, detail_list_obj):
    method check_result (line 47) | def check_result(self, future_list):
    method init_hadoop (line 56) | def init_hadoop(self, detail_obj, target_ip, service_controllers_dict,...
    method init (line 100) | def init(self, action, detail_obj_list):
    method single_service_executor (line 137) | def single_service_executor(self, detail_obj):
    method sync_port (line 156) | def sync_port(self, service_obj):
    method sync_dir (line 175) | def sync_dir(self, obj_list):
    method _get_service_port (line 183) | def _get_service_port(self, role):
    method _get_service_controllers (line 193) | def _get_service_controllers(self, ip, role):
    method _create_service (line 204) | def _create_service(self, role, detail_obj):
    method _create_detail (line 235) | def _create_detail(self, service_obj, detail_obj):
    method high_thread_executor (line 253) | def high_thread_executor(self):

FILE: omp_server/app_store/install_exec.py
  class InstallServiceExecutor (line 39) | class InstallServiceExecutor:
    method __init__ (line 43) | def __init__(self, main_id, username, timeout=300):
    method parse_origin_data (line 52) | def parse_origin_data(self, json_source_path):
    method set_hostname_analysis (line 75) | def set_hostname_analysis(self, ips_data, ip, salt_client):
    method _execute_pre_install (line 111) | def _execute_pre_install(
    method create_user_and_send_json (line 209) | def create_user_and_send_json(self, main_obj):
    method now_time (line 250) | def now_time():
    method create_history (line 254) | def create_history(self, detail_obj, is_success=True):
    method send (line 276) | def send(self, detail_obj):
    method unzip (line 349) | def unzip(self, detail_obj):
    method install (line 434) | def install(self, detail_obj):
    method init (line 511) | def init(self, detail_obj):
    method start (line 593) | def start(self, detail_obj):
    method execute_post_action (line 680) | def execute_post_action(self, queryset, post_obj):  # NOQA
    method single_service_executor (line 725) | def single_service_executor(self, detail_obj):
    method high_availability_executor (line 745) | def high_availability_executor(self, detail_obj_lst):
    method thread_poll_executor (line 763) | def thread_poll_executor(self, detail_obj_lst):
    method make_install_order (line 791) | def make_install_order(queryset):
    method execute_post_action_main (line 829) | def execute_post_action_main(self, main_obj):
    method execute_pre_install (line 865) | def execute_pre_install(self, main_obj):
    method execute_post_install (line 882) | def execute_post_install(self, main_obj):
    method get_openssl_version_from_cmd (line 932) | def get_openssl_version_from_cmd(ip, salt_client, cmd_str):
    method upgrade_openssl (line 952) | def upgrade_openssl(ip, salt_client):
    method main (line 983) | def main(self):

FILE: omp_server/app_store/install_executor.py
  class InstallServiceExecutor (line 21) | class InstallServiceExecutor:
    method __init__ (line 25) | def __init__(self, main_id, username, timeout=300):
    method now_time (line 33) | def now_time():
    method create_history (line 36) | def create_history(self, detail_obj, is_success=True):
    method send (line 57) | def send(self, detail_obj):
    method unzip (line 128) | def unzip(self, detail_obj):
    method install (line 202) | def install(self, detail_obj):
    method init (line 263) | def init(self, detail_obj):
    method start (line 341) | def start(self, detail_obj):
    method _is_base_env (line 413) | def _is_base_env(detail_obj):
    method _is_dependency (line 428) | def _is_dependency(detail_obj):
    method main (line 432) | def main(self):

FILE: omp_server/app_store/install_utils.py
  function make_lst_unique (line 42) | def make_lst_unique(lst, key_1, key_2):
  function make_editable (line 63) | def make_editable(element):
  function make_app_install_args (line 76) | def make_app_install_args(app_install_args):
  class DataJson (line 92) | class DataJson(object):
    method __init__ (line 95) | def __init__(self, operation_uuid):
    method get_ser_install_args (line 103) | def get_ser_install_args(self, obj):    # NOQA
    method parse_single_service (line 120) | def parse_single_service(self, obj):
    method make_data_json (line 138) | def make_data_json(self, json_lst):
    method run (line 155) | def run(self):
  class SerDependenceParseUtils (line 169) | class SerDependenceParseUtils(object):
    method __init__ (line 174) | def __init__(self, parse_name, parse_version):
    method get_newest_ser (line 186) | def get_newest_ser(self):
    method get_ser_instances (line 197) | def get_ser_instances(self, obj):  # NOQA
    method get_deploy_mode (line 230) | def get_deploy_mode(self, obj):     # NOQA
    method get_is_base_env (line 253) | def get_is_base_env(self, obj):     # NOQA
    method get_dependence (line 264) | def get_dependence(self, lst, dep):
    method run_ser (line 332) | def run_ser(self):
  class ProDependenceParseUtils (line 347) | class ProDependenceParseUtils(object):
    method __init__ (line 352) | def __init__(self, parse_name, parse_version):
    method get_pro_instances (line 362) | def get_pro_instances(self, obj):   # NOQA
    method get_dependence (line 374) | def get_dependence(self, lst, dep):
    method get_newest_pro (line 420) | def get_newest_pro(self):
    method run_pro (line 431) | def run_pro(self):
  class ServiceArgsSerializer (line 445) | class ServiceArgsSerializer(object):
    method get_app_dependence (line 448) | def get_app_dependence(self, obj):  # NOQA
    method get_app_port (line 458) | def get_app_port(self, obj):    # NOQA
    method get_app_install_args (line 472) | def get_app_install_args(self, obj):  # NOQA
    method get_deploy_mode (line 486) | def get_deploy_mode(self, obj):  # NOQA
    method _process_continue_parse (line 503) | def _process_continue_parse(self, obj):  # NOQA
    method get_process_continue (line 523) | def get_process_continue(self, obj):    # NOQA
    method get_process_message (line 533) | def get_process_message(self, obj):    # NOQA
  class ValidateExistService (line 544) | class ValidateExistService(object):
    method __init__ (line 547) | def __init__(self, data=None):
    method check_cluster (line 558) | def check_cluster(self, dic):   # NOQA
    method check_single (line 573) | def check_single(self, dic):    # NOQA
    method run (line 588) | def run(self):
  class ValidateInstallService (line 604) | class ValidateInstallService(object):
    method __init__ (line 607) | def __init__(self, data=None):
    method check_service_port (line 619) | def check_service_port(self, app_port, ip):     # NOQA
    method check_service_args (line 648) | def check_service_args(self, app_install_args, data_path, ip):  # NOQA
    method check_single_service (line 688) | def check_single_service(self, dic):    # NOQA
    method run (line 736) | def run(self):
  class CreateInstallPlan (line 758) | class CreateInstallPlan(object):
    method __init__ (line 761) | def __init__(self, install_data):
    method get_app_obj_for_service (line 815) | def get_app_obj_for_service(self, dic):     # NOQA
    method get_app_port_for_service (line 826) | def get_app_port_for_service(self, dic):    # NOQA
    method get_controllers_for_service (line 835) | def get_controllers_for_service(self, dic):  # NOQA
    method get_env_for_service (line 869) | def get_env_for_service(self):  # NOQA
    method create_connect_info (line 877) | def create_connect_info(self, dic):     # NOQA
    method create_cluster (line 907) | def create_cluster(self, dic):  # NOQA
    method create_service (line 928) | def create_service(self, dic):
    method create_product_instance (line 950) | def create_product_instance(self, dic):     # NOQA
    method check_if_has_post_action (line 966) | def check_if_has_post_action(self, ser):    # NOQA
    method run (line 978) | def run(self):

FILE: omp_server/app_store/new_install_serializers.py
  class BaseInstallSerializer (line 56) | class BaseInstallSerializer(Serializer):
    method validate_unique_key (line 65) | def validate_unique_key(self, unique_key):  # NOQA
  class CreateInstallInfoSerializer (line 75) | class CreateInstallInfoSerializer(BaseInstallSerializer):
    method check_product_dependence (line 105) | def check_product_dependence(self, pro_obj, all_dic):  # NOQA
    method validate_install_product (line 136) | def validate_install_product(self, install_product):  # NOQA
    method create (line 158) | def create(self, validated_data):
  class CheckInstallInfoSerializer (line 244) | class CheckInstallInfoSerializer(BaseInstallSerializer):
    method get_product_instance_name_lst (line 247) | def get_product_instance_name_lst(self):  # NOQA
    method get_cluster_name_lst (line 255) | def get_cluster_name_lst(self):  # NOQA
    method check_basic_product_instance_name_unique (line 263) | def check_basic_product_instance_name_unique(self, lst):
    method check_dependence_cluster_name_unique (line 284) | def check_dependence_cluster_name_unique(self, lst):
    method check_deploy_mode_num (line 315) | def check_deploy_mode_num(self):
    method validate_data (line 318) | def validate_data(self, data):
    method check_service (line 348) | def check_service(self, validated_data, use_exist, install):  # NOQA
    method create (line 364) | def create(self, validated_data):
  class CreateServiceDistributionSerializer (line 394) | class CreateServiceDistributionSerializer(BaseInstallSerializer):
    method get_host_info (line 401) | def get_host_info(self):  # NOQA
    method get_basic_data (line 412) | def get_basic_data(self, data, all_data, check_data):  # NOQA
    method get_denpendence_data (line 436) | def get_denpendence_data(self, data, all_data, check_data):  # NOQA
    method get_product_info (line 474) | def get_product_info(self, data, lst):  # NOQA
    method get_basic_info (line 492) | def get_basic_info(self, data, lst):  # NOQA
    method create (line 509) | def create(self, validated_data):
  class CheckServiceDistributionSerializer (line 564) | class CheckServiceDistributionSerializer(BaseInstallSerializer):
    method check_agent_status (line 575) | def check_agent_status(self, ip):
    method validate_data (line 582) | def validate_data(self, data):  # NOQA
    method create (line 623) | def create(self, validated_data):
  class CreateInstallPlanSerializer (line 675) | class CreateInstallPlanSerializer(BaseInstallSerializer):
    method check_service_dis (line 694) | def check_service_dis(self, host_service_map, install_data):  # NOQA
    method make_final_install_data (line 722) | def make_final_install_data(  # NOQA
    method check_error_msg (line 785) | def check_error_msg(self, all_install_service_lst):  # NOQA
    method create (line 799) | def create(self, validated_data):
  class MainInstallHistorySerializer (line 911) | class MainInstallHistorySerializer(serializers.ModelSerializer):
    class Meta (line 915) | class Meta:
  class CreateComponentInstallInfoSerializer (line 924) | class CreateComponentInstallInfoSerializer(Serializer):
    method validate_install_component (line 957) | def validate_install_component(self, install_component):  # NOQA
    method create (line 976) | def create(self, validated_data):
  class RetryInstallSerializer (line 1044) | class RetryInstallSerializer(Serializer):
    method validate_unique_key (line 1052) | def validate_unique_key(self, unique_key):  # NOQA
    method create (line 1064) | def create(self, validated_data):

FILE: omp_server/app_store/new_install_utils.py
  class RedisDB (line 48) | class RedisDB(object):
    method __init__ (line 53) | def __init__(self):
    method delete_keys (line 64) | def delete_keys(self, keyword):
    method set (line 73) | def set(self, name, data, timeout=60 * 60 * 8):
    method update (line 84) | def update(self, name, data, timeout=60 * 60 * 8):
    method get (line 97) | def get(self, name):
  class BaseRedisData (line 120) | class BaseRedisData(object):
    method __init__ (line 123) | def __init__(self, unique_key):
    method delete_all_keys (line 127) | def delete_all_keys(self):
    method _get (line 134) | def _get(self, key):
    method step_set_with_ser (line 146) | def step_set_with_ser(self, data):
    method get_with_ser (line 160) | def get_with_ser(self):
    method step_1_set_unique_key (line 168) | def step_1_set_unique_key(self, data):
    method get_unique_key (line 182) | def get_unique_key(self):
    method step_2_set_origin_install_data_args (line 192) | def step_2_set_origin_install_data_args(self, data):  # NOQA
    method get_step_2_origin_data (line 326) | def get_step_2_origin_data(self):
    method step_3_set_checked_data (line 334) | def step_3_set_checked_data(self, data):
    method get_step_3_checked_data (line 404) | def get_step_3_checked_data(self):
    method get_step_3_cluster_name_map (line 412) | def get_step_3_cluster_name_map(self):
    method get_step3_service_vip_map (line 420) | def get_step3_service_vip_map(self):
    method step_4_set_service_distribution (line 428) | def step_4_set_service_distribution(self, data):
    method get_step_4_service_distribution (line 458) | def get_step_4_service_distribution(self):
    method step_5_set_host_and_service_map (line 466) | def step_5_set_host_and_service_map(self, host_list, host_service_map):
    method get_step_5_host_list (line 501) | def get_step_5_host_list(self):
    method get_step_5_host_service_map (line 509) | def get_step_5_host_service_map(self):
    method step_6_set_final_data (line 517) | def step_6_set_final_data(self, data):
    method get_step_6_set_final_data (line 528) | def get_step_6_set_final_data(self):
    method set_host_user_map (line 536) | def set_host_user_map(self):
    method get_host_user_map (line 547) | def get_host_user_map(self):
  function check_package_exists (line 555) | def check_package_exists(app_obj):
  class ProductServiceParse (line 579) | class ProductServiceParse(object):
    method __init__ (line 582) | def __init__(
    method get_default_and_step (line 597) | def get_default_and_step(self, app_obj):
    method parse_single_service (line 613) | def parse_single_service(self, service_dic):
    method get_services_list (line 677) | def get_services_list(self):
    method run (line 689) | def run(self):
  class ComponentServiceParse (line 709) | class ComponentServiceParse(object):
    method __init__ (line 712) | def __init__(
    method get_deploy_mode (line 727) | def get_deploy_mode(self, app_obj):
    method parse_single_service (line 736) | def parse_single_service(self):
    method run (line 777) | def run(self):
  function make_lst_unique (line 785) | def make_lst_unique(lst, key_1, key_2):
  class SerDependenceParseUtils (line 820) | class SerDependenceParseUtils(object):
    method __init__ (line 825) | def __init__(self, parse_name, parse_version, high_availability=False):
    method get_newest_ser (line 841) | def get_newest_ser(self):
    method get_ser_instances (line 852) | def get_ser_instances(self, obj):  # NOQA
    method get_is_base_env (line 897) | def get_is_base_env(self, obj):  # NOQA
    method get_dependence (line 917) | def get_dependence(self, lst, dep):
    method run_ser (line 977) | def run_ser(self):
  class SerDeployModeUtils (line 992) | class SerDeployModeUtils(object):
    method __init__ (line 995) | def __init__(self, ser_name, high_availability=False, host_num=0):
    method get (line 1000) | def get(self):
  class SerRoleUtils (line 1017) | class SerRoleUtils(object):
    method get (line 1021) | def get(install_services):
  class SerVipUtils (line 1046) | class SerVipUtils(object):
    method __init__ (line 1049) | def __init__(
    method get_keep_alive (line 1057) | def get_keep_alive(self, ip, data_folder, name):
    method run (line 1088) | def run(self):
  class SerWithUtils (line 1106) | class SerWithUtils(object):
    method __init__ (line 1109) | def __init__(self, ser_name, ser_version):
    method run (line 1118) | def run(self):
  class ServiceArgsPortUtils (line 1135) | class ServiceArgsPortUtils(object):
    method __init__ (line 1138) | def __init__(self, ip=None, data_folder=None,
    method get_product_config (line 1146) | def get_product_config():
    method inner_replace_args (line 1160) | def inner_replace_args(target_lst, config_lst):
    method make_product_config_overwrite (line 1183) | def make_product_config_overwrite(self, app_name, rep_type, lst):
    method make_editable (line 1203) | def make_editable(element):
    method get_app_dependence (line 1215) | def get_app_dependence(self, obj):  # NOQA
    method get_app_port (line 1225) | def get_app_port(self, obj):  # NOQA
    method format_app_install_args (line 1244) | def format_app_install_args(self, app_install_args):  # NOQA
    method get_app_install_args (line 1258) | def get_app_install_args(self, obj):  # NOQA
    method reformat_install_args (line 1280) | def reformat_install_args(self, install_args):
    method remake_install_args (line 1289) | def remake_install_args(self, obj):
    method _parse (line 1305) | def _parse(self, app_install_args):
  class ValidateInstallService (line 1328) | class ValidateInstallService(object):
    method __init__ (line 1331) | def __init__(self, data=None):
    method check_service_port (line 1343) | def check_service_port(self, app_port, ip):  # NOQA
    method check_service_args (line 1371) | def check_service_args(self, app_install_args, data_path, ip):  # NOQA
    method check_single_service (line 1405) | def check_single_service(self, dic):  # NOQA
    method run (line 1434) | def run(self):
  class BaseEnvServiceUtils (line 1455) | class BaseEnvServiceUtils(object):
    method __init__ (line 1458) | def __init__(self, all_install_service_lst, host_user_map):
    method _dep_parse (line 1467) | def _dep_parse(self, dep_lst, base_env_dic, base_env_ser_lst, item):  ...
    method run (line 1519) | def run(self):
  class WithServiceUtils (line 1545) | class WithServiceUtils(object):
    method __init__ (line 1548) | def __init__(self, all_install_service_lst,
    method parse_single_service (line 1566) | def parse_single_service(self, ser_dic):
    method run (line 1651) | def run(self):
  class DataJson (line 1664) | class DataJson(object):
    method __init__ (line 1667) | def __init__(self, operation_uuid, service_obj=None):
    method get_ser_install_args (line 1677) | def get_ser_install_args(self, obj):  # NOQA
    method parse_single_service (line 1694) | def parse_single_service(self, obj):
    method make_data_json (line 1716) | def make_data_json(self, json_lst):
    method run (line 1733) | def run(self):
  class CreateInstallPlan (line 1759) | class CreateInstallPlan(object):
    method __init__ (line 1762) | def __init__(self, all_install_service_lst, unique_key=None):
    method get_app_obj_for_service (line 1771) | def get_app_obj_for_service(self, dic):  # NOQA
    method get_controllers_for_service (line 1782) | def get_controllers_for_service(self, dic):  # NOQA
    method get_env_for_service (line 1816) | def get_env_for_service(self):  # NOQA
    method create_connect_info (line 1824) | def create_connect_info(self, dic):  # NOQA
    method create_cluster (line 1854) | def create_cluster(self, dic):  # NOQA
    method _get_exist_dep (line 1875) | def _get_exist_dep(self, inner):
    method _get_install_dep (line 1896) | def _get_install_dep(self, inner):
    method get_dependence (line 1921) | def get_dependence(self, dic):
    method create_service (line 1960) | def create_service(self, dic):
    method create_product_instance (line 1985) | def create_product_instance(self, dic):  # NOQA
    method check_if_has_post_action (line 2006) | def check_if_has_post_action(self, ser):  # NOQA
    method create_pre_install_history (line 2018) | def create_pre_install_history(self, main_obj):
    method create_post_install_history (line 2034) | def create_post_install_history(self, main_obj):
    method run (line 2059) | def run(self):
  class MakeServiceOrder (line 2124) | class MakeServiceOrder(object):
    method __init__ (line 2125) | def __init__(self, all_service):
    method run (line 2128) | def run(self):
    method make_install_order (line 2131) | def make_install_order(self):
  class ValidateInstallServicePortArgs (line 2167) | class ValidateInstallServicePortArgs(object):
    method __init__ (line 2170) | def __init__(self, data=None):
    method check_service_port (line 2182) | def check_service_port(self, app_port, ip):  # NOQA
    method check_service_args (line 2211) | def check_service_args(self, app_install_args, data_path, ip):  # NOQA
    method check_single_service (line 2251) | def check_single_service(self, dic):  # NOQA
    method run (line 2281) | def run(self):

FILE: omp_server/app_store/new_install_view.py
  class BatchInstallEntranceView (line 45) | class BatchInstallEntranceView(GenericViewSet, ListModelMixin):
    method check_product_instance (line 54) | def check_product_instance(pro_name, pro_version_lst):
    method list (line 76) | def list(self, request, *args, **kwargs):
  class CreateInstallInfoView (line 123) | class CreateInstallInfoView(GenericViewSet, CreateModelMixin):
  class CheckInstallInfoView (line 128) | class CheckInstallInfoView(GenericViewSet, CreateModelMixin):
  class CreateServiceDistributionView (line 133) | class CreateServiceDistributionView(GenericViewSet, CreateModelMixin):
  class CheckServiceDistributionView (line 138) | class CheckServiceDistributionView(GenericViewSet, CreateModelMixin):
  class GetInstallHostRangeView (line 143) | class GetInstallHostRangeView(GenericViewSet, ListModelMixin):
    method list (line 146) | def list(self, request, *args, **kwargs):
  class GetInstallArgsByIpView (line 166) | class GetInstallArgsByIpView(GenericViewSet, ListModelMixin):
    method list (line 169) | def list(self, request, *args, **kwargs):
  class CreateInstallPlanView (line 228) | class CreateInstallPlanView(GenericViewSet, CreateModelMixin):
  class ListServiceByIpView (line 233) | class ListServiceByIpView(GenericViewSet, ListModelMixin):
    method list (line 234) | def list(self, request, *args, **kwargs):
  class ShowInstallProcessView (line 256) | class ShowInstallProcessView(GenericViewSet, ListModelMixin):
    method list (line 257) | def list(self, request, *args, **kwargs):
  class ShowSingleServiceInstallLogView (line 338) | class ShowSingleServiceInstallLogView(GenericViewSet, ListModelMixin):
    method get_pre_install_log (line 340) | def get_pre_install_log(self, main_obj, ip):
    method get_post_install_log (line 351) | def get_post_install_log(self, main_obj, ip):
    method list (line 362) | def list(self, request, *args, **kwargs):
  class MainInstallHistoryView (line 402) | class MainInstallHistoryView(GenericViewSet, ListModelMixin):
  class CreateComponentInstallInfoView (line 408) | class CreateComponentInstallInfoView(GenericViewSet, CreateModelMixin):
  class RetryInstallView (line 413) | class RetryInstallView(GenericViewSet, CreateModelMixin):

FILE: omp_server/app_store/post_install_utils/base.py
  class BasePostInstallUtils (line 15) | class BasePostInstallUtils(object):
    method __init__ (line 18) | def __init__(self, main_obj):
    method send_json (line 24) | def send_json(self, detail_obj):
    method execute_install (line 42) | def execute_install(self, detail_obj):
    method execute_init (line 64) | def execute_init(self, detail_obj):
    method execute_restart (line 86) | def execute_restart(self, detail_obj):
    method get_install_path (line 102) | def get_install_path(self, detail_obj):
    method get_init_path (line 110) | def get_init_path(self, detail_obj):
    method get_restart_path (line 118) | def get_restart_path(self, detail_obj):

FILE: omp_server/app_store/post_install_utils/nacos.py
  class Nacos (line 19) | class Nacos(BasePostInstallUtils):
    method run (line 22) | def run(self):

FILE: omp_server/app_store/post_install_utils/tengine.py
  class Tengine (line 19) | class Tengine(BasePostInstallUtils):
    method run (line 22) | def run(self):

FILE: omp_server/app_store/service_splitting.py
  function service_log_splitting (line 13) | def service_log_splitting(obj_id, split_service_ids):
  function service_splitting (line 37) | def service_splitting(doim_ids):

FILE: omp_server/app_store/tasks.py
  class PublicAction (line 41) | class PublicAction(object):
    method __init__ (line 42) | def __init__(self, md5):
    method update_package_status (line 45) | def update_package_status(self, status, msg=None):
    method update_fail_status (line 49) | def update_fail_status(self, msg=None):
  class FiledCheck (line 53) | class FiledCheck(object):
    method __init__ (line 64) | def __init__(self, yaml_dir, db_obj):
    method strong_check (line 68) | def strong_check(self, settings, field=None, is_weak=False, ignore=Non...
    method weak_check (line 104) | def weak_check(self, settings, field, attention=""):
  function front_end_verified (line 134) | def front_end_verified(uuid, operation_user, package_name, random_str, v...
  class ExplainYml (line 349) | class ExplainYml:
    method __init__ (line 357) | def __init__(self, db_obj, yaml_dir):
    method check_book_tools (line 364) | def check_book_tools(self, key, value):
    method explain_yml (line 379) | def explain_yml(self):
    method product (line 437) | def product(self, settings):
    method service_component (line 474) | def service_component(self, settings):
    method service (line 531) | def service(self, settings):
    method upgrade (line 544) | def upgrade(self, settings):
    method component (line 547) | def component(self, settings):
  function exec_clear (line 576) | def exec_clear(clear_dir):
  function clear_check (line 595) | def clear_check(need_rm):
  function publish_bak_end (line 613) | def publish_bak_end(uuid, exc_len):
  function publish_entry (line 652) | def publish_entry(uuid):
  function check_monitor_data (line 757) | def check_monitor_data(detail_obj):
  function add_prometheus (line 820) | def add_prometheus(main_history_id, queryset=None):
  function make_inspection (line 890) | def make_inspection(username):
  function install_service (line 919) | def install_service(main_history_id, username="admin"):

FILE: omp_server/app_store/tmp_exec_back_task.py
  class RedisLock (line 22) | class RedisLock(object):
    method __init__ (line 23) | def __init__(self, host='127.0.0.1', port='6379', db=9, **kwargs):
    method args_init (line 27) | def args_init(host, port, db, kwargs):
    method get_lock (line 32) | def get_lock(self, key='back_end_verified'):
  function back_end_verified_init (line 38) | def back_end_verified_init(operation_user):
  function front_end_verified_init (line 76) | def front_end_verified_init(uuid, operation_user, package_name, obj_id, ...

FILE: omp_server/app_store/upload_task.py
  class CreateDatabase (line 14) | class CreateDatabase(object):
    method __init__ (line 22) | def __init__(self, json_data):
    method str_to_bool (line 26) | def str_to_bool(self, value):
    method explain (line 34) | def explain(self, data, default=None):
    method explain_dependence (line 46) | def explain_dependence(self):
    method create_product (line 56) | def create_product(self):
    method create_service (line 99) | def create_service(self, service, app_obj):
    method create_component (line 175) | def create_component(self):
    method create_pro_app_lab (line 224) | def create_pro_app_lab(self, obj):
    method create_lab (line 237) | def create_lab(self):

FILE: omp_server/app_store/views.py
  class AppStoreListView (line 63) | class AppStoreListView(GenericViewSet, ListModelMixin):
    method list (line 66) | def list(self, request, *args, **kwargs):
  class LabelListView (line 83) | class LabelListView(GenericViewSet, ListModelMixin):
    method list (line 95) | def list(self, request, *args, **kwargs):
  class ComponentListView (line 111) | class ComponentListView(AppStoreListView):
    method list (line 128) | def list(self, request, *args, **kwargs):
  class ServiceListView (line 133) | class ServiceListView(AppStoreListView):
    method list (line 148) | def list(self, request, *args, **kwargs):
  class UploadPackageView (line 153) | class UploadPackageView(GenericViewSet, CreateModelMixin):
  class RemovePackageView (line 164) | class RemovePackageView(GenericViewSet, CreateModelMixin):
  class ComponentDetailView (line 175) | class ComponentDetailView(GenericViewSet, ListModelMixin):
    method list (line 184) | def list(self, request, *args, **kwargs):
  class ServiceDetailView (line 200) | class ServiceDetailView(GenericViewSet, ListModelMixin):
    method list (line 209) | def list(self, request, *args, **kwargs):
  class ServicePackPageVerificationView (line 225) | class ServicePackPageVerificationView(GenericViewSet, ListModelMixin):
  class PublishViewSet (line 233) | class PublishViewSet(ListModelMixin, CreateModelMixin, GenericViewSet):
    method create (line 247) | def create(self, request, *args, **kwargs):
  class ExecuteLocalPackageScanView (line 256) | class ExecuteLocalPackageScanView(GenericViewSet, CreateModelMixin):
    method create (line 265) | def create(self, request, *args, **kwargs):
  class LocalPackageScanResultView (line 281) | class LocalPackageScanResultView(GenericViewSet, ListModelMixin):
    method get_res_data (line 291) | def get_res_data(operation_uuid, package_names):
    method check_request_param (line 380) | def check_request_param(operation_uuid, package_names):
    method list (line 393) | def list(self, request, *args, **kwargs):
  class ApplicationTemplateView (line 401) | class ApplicationTemplateView(BaseDownLoadTemplateView):
    method list (line 409) | def list(self, request, *args, **kwargs):
  class DeploymentOperableView (line 415) | class DeploymentOperableView(GenericViewSet, ListModelMixin):
    method list (line 425) | def list(self, request, *args, **kwargs):
  class DeploymentTemplateView (line 429) | class DeploymentTemplateView(BaseDownLoadTemplateView):
    method list (line 437) | def list(self, request, *args, **kwargs):
  class DeploymentPlanListView (line 443) | class DeploymentPlanListView(GenericViewSet, ListModelMixin):
  class DeploymentPlanValidateView (line 455) | class DeploymentPlanValidateView(GenericViewSet, CreateModelMixin):
    method create (line 464) | def create(self, request, *args, **kwargs):
  class DeploymentPlanImportView (line 472) | class DeploymentPlanImportView(GenericViewSet, CreateModelMixin):
    method _get_app_pro_queryset (line 482) | def _get_app_pro_queryset(service_name_ls):
    method _add_service (line 507) | def _add_service(service_obj_ls, host_obj, app_obj, env_obj, only_dict,
    method create (line 610) | def create(self, request, *args, **kwargs):
  class ExecutionRecordAPIView (line 985) | class ExecutionRecordAPIView(GenericViewSet, ListModelMixin):
  class ProductCompositionView (line 997) | class ProductCompositionView(GenericViewSet, ListModelMixin,
    method get_queryset (line 1007) | def get_queryset(self):
    method list (line 1010) | def list(self, request, *args, **kwargs):
    method create (line 1016) | def create(self, request, *args, **kwargs):
  class DeleteAppStorePackageView (line 1032) | class DeleteAppStorePackageView(GenericViewSet, ListModelMixin, CreateMo...
    method get_queryset (line 1040) | def get_queryset(self):
    method get_serializer_class (line 1047) | def get_serializer_class(self):
    method list (line 1052) | def list(self, request, *args, **kwargs):
    method explain_info (line 1070) | def explain_info():
    method check_service (line 1089) | def check_service(self, params):
    method del_file (line 1116) | def del_file(file_path):
    method del_database (line 1123) | def del_database(self, ser_id, pro_dc):
    method create (line 1144) | def create(self, request, *args, **kwargs):

FILE: omp_server/app_store/views_for_install.py
  class ComponentEntranceView (line 38) | class ComponentEntranceView(GenericViewSet, ListModelMixin):
    method list (line 52) | def list(self, request, *args, **kwargs):
  class ProductEntranceView (line 68) | class ProductEntranceView(GenericViewSet, ListModelMixin):
  class ExecuteInstallView (line 82) | class ExecuteInstallView(GenericViewSet, CreateModelMixin):
    method create (line 87) | def create(self, request, *args, **kwargs):
  class InstallHistoryView (line 102) | class InstallHistoryView(GenericViewSet, ListModelMixin):
  class ServiceInstallHistoryDetailView (line 114) | class ServiceInstallHistoryDetailView(GenericViewSet, ListModelMixin):

FILE: omp_server/backups/apps.py
  class BackupsConfig (line 7) | class BackupsConfig(AppConfig):

FILE: omp_server/backups/backups_serializers.py
  class BackupHistoryIdsSerializer (line 14) | class BackupHistoryIdsSerializer(ModelSerializer):
    method validate (line 24) | def validate(self, attrs):
    class Meta (line 31) | class Meta:
  class BackupHistorySerializer (line 36) | class BackupHistorySerializer(ModelSerializer):
    class Meta (line 37) | class Meta:
  class BackupCustomSerializer (line 43) | class BackupCustomSerializer(ModelSerializer):
    method validate (line 50) | def validate(self, attrs):
    class Meta (line 57) | class Meta:
  class BackupCustomRepeatSerializer (line 62) | class BackupCustomRepeatSerializer(ModelSerializer):
    method get_name (line 65) | def get_name(self, obj):
    class Meta (line 71) | class Meta:
  class BackupSettingSerializer (line 76) | class BackupSettingSerializer(ModelSerializer):
    method validate_retain_path (line 97) | def validate_retain_path(self, retain_path):  # NOQA
    method validate_crontab_detail (line 110) | def validate_crontab_detail(self, crontab_detail):  # NOQA
    class Meta (line 115) | class Meta:

FILE: omp_server/backups/backups_utils.py
  function cmd (line 23) | def cmd(command):
  function tar_files (line 33) | def tar_files(source_path, target_path):
  function transfer_week (line 60) | def transfer_week(day_of_week):
  function exec_scripts (line 74) | def exec_scripts(exec_json, host_i_d, his_id):
  function change_status (line 112) | def change_status(obj, result, message=""):
  function check_result (line 121) | def check_result(future_list, his_ls):
  function get_backup_info (line 128) | def get_backup_info(service_obj):
  function backup_service_data (line 166) | def backup_service_data(his_ls):
  function rm_backend_file (line 197) | def rm_backend_file(his_objs):
  function check_ing (line 219) | def check_ing(obj):

FILE: omp_server/backups/tasks.py
  function backup_service (line 24) | def backup_service(**kwargs):
  function pull_back_file (line 71) | def pull_back_file(his_id, remote_path, ip):

FILE: omp_server/backups/views.py
  class CanBackupInstancesView (line 27) | class CanBackupInstancesView(GenericViewSet, ListModelMixin):
    method list (line 33) | def list(self, request, *args, **kwargs):
  class BackupSettingView (line 46) | class BackupSettingView(GenericViewSet, ListModelMixin,
    method create (line 58) | def create(self, request, *args, **kwargs):
    method update (line 80) | def update(self, request, *args, **kwargs):
    method destroy (line 91) | def destroy(self, request, *args, **kwargs):
  class BackupHistoryView (line 99) | class BackupHistoryView(GenericViewSet, ListModelMixin,
    method get_serializer_class (line 114) | def get_serializer_class(self):
    method create (line 119) | def create(self, request, *args, **kwargs):
    method update (line 128) | def update(self, request, *args, **kwargs):
  class BackupCustomView (line 151) | class BackupCustomView(GenericViewSet, ListModelMixin,
    method create (line 165) | def create(self, request, *args, **kwargs):
  class BackupCustomRepeatView (line 172) | class BackupCustomRepeatView(GenericViewSet, ListModelMixin):
    method get_queryset (line 182) | def get_queryset(self):

FILE: omp_server/db_models/apps.py
  class DbModelsConfig (line 4) | class DbModelsConfig(AppConfig):
    method ready (line 7) | def ready(self):

FILE: omp_server/db_models/migrations/0001_initial.py
  class Migration (line 10) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0002_auto_20211202_1830.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0003_host_init_status.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0004_auto_20211203_1617.py
  class Migration (line 7) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0005_auto_20211206_1723.py
  class Migration (line 7) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0005_update_init_status.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0006_merge_20211206_1833.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0007_deploymentplan.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0008_service_vip.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0009_auto_20211228_1603.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0010_auto_20220114_1830.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0010_backuphistory_backupsetting.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0011_auto_20220112_1607.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0012_auto_20220112_1653.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0013_merge_20220114_1838.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0014_auto_20220121_1616.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0015_executionrecord.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0016_auto_20220125_1800.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0017_selfhealinghistory_selfhealingsetting.py
  class Migration (line 7) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0018_userloginlog_request_result.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0019_toolexecutedetailhistory_toolexecutemainhistory_toolinfo_uploadfilehistory.py
  class Migration (line 8) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0020_init_tools.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0021_customscript.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0022_alertrule_rule.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0023_auto_20220225_1747.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0024_auto_20220226_1300.py
  function update_tool_logo (line 11) | def update_tool_logo(apps, schema_editor):
  class Migration (line 23) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0025_alertrule_forbidden.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0026_alertrule_hash_data.py
  function get_hash_value (line 9) | def get_hash_value(expr, severity):
  function update_hash_data (line 15) | def update_hash_data(apps, schema_editor):
  class Migration (line 23) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0026_auto_20220303_1527.py
  function combine_names (line 8) | def combine_names(apps, schema_editor):
  class Migration (line 18) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0027_merge_20220304_2000.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0028_auto_20220304_2001.py
  function update_execution_record (line 10) | def update_execution_record(apps, schema_editor):
  class Migration (line 17) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0029_auto_20230110_1739.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0030_auto_20230711_1739.py
  class Migration (line 7) | class Migration(migrations.Migration):

FILE: omp_server/db_models/migrations/0031_auto_20230921_1128.py
  class Migration (line 6) | class Migration(migrations.Migration):

FILE: omp_server/db_models/mixins.py
  class TimeStampMixin (line 7) | class TimeStampMixin(models.Model):
    class Meta (line 15) | class Meta:
  class DeleteMixin (line 19) | class DeleteMixin(models.Model):
    method delete (line 24) | def delete(self, using=None, soft=True, *args, **kwargs):
    class Meta (line 31) | class Meta:
  class UpgradeStateChoices (line 35) | class UpgradeStateChoices(models.IntegerChoices):
  class UpgradeStateMixin (line 43) | class UpgradeStateMixin(models.Model):
    class Meta (line 51) | class Meta:
  class RollbackStateChoices (line 55) | class RollbackStateChoices(models.IntegerChoices):
  class RollBackStateMixin (line 62) | class RollBackStateMixin(models.Model):
    class Meta (line 70) | class Meta:

FILE: omp_server/db_models/models/backup.py
  class BackupCustom (line 8) | class BackupCustom(models.Model):
    class Meta (line 13) | class Meta:
  class BackupSetting (line 18) | class BackupSetting(models.Model):
    class Meta (line 28) | class Meta:
  class BackupHistory (line 33) | class BackupHistory(TimeStampMixin):
    class Meta (line 57) | class Meta:
    method fetch_file_kwargs (line 61) | def fetch_file_kwargs(self):

FILE: omp_server/db_models/models/custom_metric.py
  class CustomScript (line 12) | class CustomScript(TimeStampMixin):
    method valid_upload_file (line 31) | def valid_upload_file(self, *args, **kwargs):  # NOQA
    method upload_file_url (line 34) | def upload_file_url(self, file_name, **kwargs):  # NOQA
    class Meta (line 37) | class Meta:

FILE: omp_server/db_models/models/email.py
  class EmailSMTPSetting (line 14) | class EmailSMTPSetting(models.Model):
    class Meta (line 22) | class Meta:
    method get_dict (line 34) | def get_dict(self):
    method email_url (line 43) | def email_url(self):
    method update_config (line 54) | def update_config(self, key):
    method reload_alert_manage (line 70) | def reload_alert_manage():
    method set_omp_conf (line 83) | def set_omp_conf(self):
    method set_alert_manage_config (line 101) | def set_alert_manage_config(self):
    method update_setting_config (line 134) | def update_setting_config(self):
  class ModuleSendEmailSetting (line 143) | class ModuleSendEmailSetting(models.Model):
    class Meta (line 150) | class Meta:
    method get_email_settings (line 155) | def get_email_settings(cls, env_id, module):
    method update_email_settings (line 165) | def update_email_settings(cls, env_id, module, send_email, to_users):

FILE: omp_server/db_models/models/env.py
  class Env (line 4) | class Env(models.Model):
    class Meta (line 13) | class Meta:

FILE: omp_server/db_models/models/execution.py
  class ModuleChoices (line 5) | class ModuleChoices(models.TextChoices):
  class StateChoices (line 11) | class StateChoices(models.TextChoices):
  class ExecutionRecord (line 30) | class ExecutionRecord(TimeStampMixin):
    class Meta (line 55) | class Meta:

FILE: omp_server/db_models/models/host.py
  class Host (line 7) | class Host(TimeStampMixin, DeleteMixin):
    class Meta (line 102) | class Meta:
  class HostOperateLog (line 109) | class HostOperateLog(models.Model):
    class Meta (line 124) | class Meta:

FILE: omp_server/db_models/models/inspection.py
  class InspectionHistory (line 8) | class InspectionHistory(models.Model):
    class Meta (line 46) | class Meta:
    method send_email_content (line 51) | def send_email_content(self):
    method fetch_file_kwargs (line 57) | def fetch_file_kwargs(self):
  class InspectionCrontab (line 66) | class InspectionCrontab(models.Model):
    class Meta (line 89) | class Meta:
  class InspectionReport (line 96) | class InspectionReport(models.Model):
    class Meta (line 112) | class Meta:

FILE: omp_server/db_models/models/install.py
  class MainInstallHistory (line 7) | class MainInstallHistory(TimeStampMixin):
    class Meta (line 41) | class Meta:
    method execution_record_state (line 47) | def execution_record_state(self):
    method operate_count (line 51) | def operate_count(self, exclude_service_ids=None):
    method module_id (line 61) | def module_id(self):
  class PreInstallHistory (line 65) | class PreInstallHistory(TimeStampMixin):
    class Meta (line 82) | class Meta:
  class PostInstallHistory (line 88) | class PostInstallHistory(TimeStampMixin):
    class Meta (line 106) | class Meta:
  class DetailInstallHistory (line 112) | class DetailInstallHistory(TimeStampMixin):
    class Meta (line 170) | class Meta:
    method __str__ (line 175) | def __str__(self):
  class DeploymentPlan (line 179) | class DeploymentPlan(models.Model):
    class Meta (line 199) | class Meta:

FILE: omp_server/db_models/models/monitor.py
  class MonitorUrl (line 6) | class MonitorUrl(models.Model):
    class Meta (line 15) | class Meta:
  class Alert (line 21) | class Alert(models.Model):
    class Meta (line 59) | class Meta:
  class Maintain (line 65) | class Maintain(models.Model):
    class Meta (line 78) | class Meta:
  class GrafanaMainPage (line 84) | class GrafanaMainPage(models.Model):
    class Meta (line 91) | class Meta:
  class AlertSendWaySetting (line 97) | class AlertSendWaySetting(models.Model):
    class Meta (line 105) | class Meta:
    method get_email_dict (line 127) | def get_email_dict(self):
    method get_v1_5_email_dict (line 134) | def get_v1_5_email_dict(cls, env_id):
    method get_self_dict (line 149) | def get_self_dict(self):
    method update_email_config (line 165) | def update_email_config(cls, used, user_emails):

FILE: omp_server/db_models/models/product.py
  class Labels (line 6) | class Labels(models.Model):
    class Meta (line 22) | class Meta:
  class UploadPackageHistory (line 28) | class UploadPackageHistory(TimeStampMixin, DeleteMixin):
    class Meta (line 72) | class Meta:
  class ProductHub (line 78) | class ProductHub(TimeStampMixin):
    class Meta (line 113) | class Meta:
  class ApplicationHub (line 119) | class ApplicationHub(TimeStampMixin):
    class Meta (line 178) | class Meta:
    method pro_info (line 186) | def pro_info(self):
  class Product (line 193) | class Product(TimeStampMixin):
    class Meta (line 205) | class Meta:

FILE: omp_server/db_models/models/self_heal.py
  class WaitSelfHealing (line 5) | class WaitSelfHealing(models.Model):
    class Meta (line 11) | class Meta:
  class SelfHealingSetting (line 16) | class SelfHealingSetting(models.Model):
    class Meta (line 29) | class Meta:
  class SelfHealingHistory (line 34) | class SelfHealingHistory(models.Model):
    class Meta (line 57) | class Meta:

FILE: omp_server/db_models/models/service.py
  class ServiceConnectInfo (line 12) | class ServiceConnectInfo(TimeStampMixin):
    class Meta (line 32) | class Meta:
  class ClusterInfo (line 38) | class ClusterInfo(TimeStampMixin, DeleteMixin):
    class Meta (line 68) | class Meta:
    method __str__ (line 73) | def __str__(self):
  class ExcludeSplit (line 77) | class ExcludeSplit(models.Manager):
    method get_queryset (line 82) | def get_queryset(self):
  class AfterSplit (line 86) | class AfterSplit(models.Manager):
    method get_queryset (line 91) | def get_queryset(self):
  class AllManage (line 95) | class AllManage(models.Manager):
    method get_queryset (line 96) | def get_queryset(self):
  class Service (line 100) | class Service(TimeStampMixin):
    class Meta (line 202) | class Meta:
    method update_port (line 208) | def update_port(self, app_ports):
    method update_controllers (line 226) | def update_controllers(self, application, install_folder):
    method update_service_connect_info (line 260) | def update_service_connect_info(self):
    method update_dependence (line 286) | def update_dependence(cls, service_dependence, app_dependence):
    method update_application (line 314) | def update_application(self, application, success, install_folder):
  class ServiceHistory (line 343) | class ServiceHistory(models.Model):
    class Meta (line 359) | class Meta:
    method create_history (line 366) | def create_history(cls, service, operation_obj=None, **kwargs):

FILE: omp_server/db_models/models/threshold.py
  class HostThreshold (line 7) | class HostThreshold(models.Model):
    class Meta (line 22) | class Meta:
    method get_dic (line 25) | def get_dic(self):
    method __str__ (line 33) | def __str__(self):
  class ServiceThreshold (line 38) | class ServiceThreshold(models.Model):
    class Meta (line 53) | class Meta:
    method get_dic (line 56) | def get_dic(self):
    method __str__ (line 64) | def __str__(self):
  class ServiceCustomThreshold (line 69) | class ServiceCustomThreshold(models.Model):
    class Meta (line 85) | class Meta:
  class Rule (line 90) | class Rule(models.Model):
    class Meta (line 99) | class Meta:
  class AlertRule (line 109) | class AlertRule(models.Model):
    class Meta (line 138) | class Meta:

FILE: omp_server/db_models/models/tool.py
  class ToolInfo (line 27) | class ToolInfo(TimeStampMixin):
    class Meta (line 110) | class Meta:
    method load_default_form (line 115) | def load_default_form(self):
    method package_name (line 127) | def package_name(self):
    method templates (line 131) | def templates(self):
    method tar_url (line 143) | def tar_url(self):
    method valid_upload_file (line 146) | def valid_upload_file(self, *args, **kwargs):
    method upload_file_url (line 149) | def upload_file_url(self, file_name, **kwargs):
  class ToolExecuteMainHistory (line 153) | class ToolExecuteMainHistory(models.Model):
    class Meta (line 183) | class Meta:
    method duration (line 189) | def duration(self):
    method get_input_files (line 194) | def get_input_files(self):
  class ToolExecuteDetailHistory (line 202) | class ToolExecuteDetailHistory(TimeStampMixin):
    class Meta (line 240) | class Meta:
    method get_data_dir (line 246) | def get_data_dir(self):
    method get_tools_dir (line 255) | def get_tools_dir(self):
    method get_cmd_str (line 267) | def get_cmd_str(self):
    method get_send_files (line 287) | def get_send_files(self):
    method get_receive_files (line 309) | def get_receive_files(self):

FILE: omp_server/db_models/models/upgrade.py
  class UpgradeHistory (line 11) | class UpgradeHistory(UpgradeStateMixin, TimeStampMixin):
    class Meta (line 32) | class Meta:
    method can_roll_back (line 37) | def can_roll_back(self):
    method execution_record_state (line 47) | def execution_record_state(self):
    method operate_count (line 51) | def operate_count(self, exclude_service_ids=None):
    method module_id (line 61) | def module_id(self):
  class UpgradeDetail (line 65) | class UpgradeDetail(UpgradeStateMixin, TimeStampMixin):
    class Meta (line 98) | class Meta:
    method get_service_history (line 102) | def get_service_history(self):
  class RollbackHistory (line 116) | class RollbackHistory(RollBackStateMixin, TimeStampMixin):
    class Meta (line 127) | class Meta:
    method execution_record_state (line 132) | def execution_record_state(self):
    method operate_count (line 136) | def operate_count(self, exclude_service_ids=None):
    method module_id (line 148) | def module_id(self):
  class RollbackDetail (line 152) | class RollbackDetail(RollBackStateMixin, TimeStampMixin):
    class Meta (line 166) | class Meta:
    method get_service_history (line 170) | def get_service_history(self):

FILE: omp_server/db_models/models/upload.py
  class UploadFileHistory (line 15) | class UploadFileHistory(TimeStampMixin):
    class Meta (line 38) | class Meta:
    method format_file_name (line 43) | def format_file_name(cls, file_name):
    method location (line 52) | def location(cls, file, module_obj=None, user=None, **kwargs):

FILE: omp_server/db_models/models/user.py
  class UserProfile (line 5) | class UserProfile(AbstractUser):
    class Meta (line 9) | class Meta:
    method __str__ (line 14) | def __str__(self):
  class OperateLog (line 19) | class OperateLog(models.Model):
    class Meta (line 40) | class Meta:
  class UserLoginLog (line 46) | class UserLoginLog(models.Model):
    class Meta (line 60) | class Meta:

FILE: omp_server/db_models/receivers/execution_record.py
  function create_execution_record (line 9) | def create_execution_record(instance, created=False, *args, **kwargs):
  function install_execution_record (line 31) | def install_execution_record(sender, instance, *args, **kwargs):
  function upgrade_execution_record (line 36) | def upgrade_execution_record(sender, instance, created, *args, **kwargs):
  function rollback_execution_record (line 41) | def rollback_execution_record(sender, instance, created, *args, **kwargs):

FILE: omp_server/db_models/receivers/service.py
  function update_upgrade_history (line 11) | def update_upgrade_history(history, union_server):
  function update_rollback_history (line 22) | def update_rollback_history(history, union_server):
  function update_execution_record (line 34) | def update_execution_record(sender, instance, *args, **kwargs):
  function update_self_health (line 69) | def update_self_health(sender, instance, *args, **kwargs):
  function delete_self_health (line 80) | def delete_self_health(sender, instance, *args, **kwargs):

FILE: omp_server/hosts/apps.py
  class HostsConfig (line 4) | class HostsConfig(AppConfig):

FILE: omp_server/hosts/hosts_filters.py
  class HostFilter (line 10) | class HostFilter(FilterSet):
    class Meta (line 15) | class Meta:
  class HostOperateFilter (line 20) | class HostOperateFilter(FilterSet):
    class Meta (line 26) | class Meta:

FILE: omp_server/hosts/hosts_serializers.py
  class HostUninstallSerializer (line 40) | class HostUninstallSerializer(ModelSerializer):
    class Meta (line 41) | class Meta:
    method validate (line 46) | def validate(self, attrs):
    method create (line 62) | def create(self, validated_data):
  class HostSerializer (line 72) | class HostSerializer(ModelSerializer):
    class Meta (line 163) | class Meta:
    method validate_instance_name (line 183) | def validate_instance_name(self, instance_name):
    method validate_ip (line 192) | def validate_ip(self, ip):
    method validate_data_folder (line 202) | def validate_data_folder(self, data_folder):
    method validate_operate_system (line 210) | def validate_operate_system(self, operate_system):
    method validate (line 217) | def validate(self, attrs):
    method create (line 284) | def create(self, validated_data):
    method update (line 307) | def update(self, instance, validated_data):
  class HostOperateLogSerializer (line 334) | class HostOperateLogSerializer(ModelSerializer):
    class Meta (line 337) | class Meta:
  class HostDetailSerializer (line 343) | class HostDetailSerializer(ModelSerializer):
    class Meta (line 350) | class Meta:
    method get_deployment_information (line 356) | def get_deployment_information(self, obj):
  class HostFieldCheckSerializer (line 375) | class HostFieldCheckSerializer(ModelSerializer):
    class Meta (line 393) | class Meta:
    method validate (line 398) | def validate(self, attrs):
  class HostMaintenanceSerializer (line 414) | class HostMaintenanceSerializer(HostIdsSerializer):
    method write_host_log (line 422) | def write_host_log(self, host_queryset, status, result):
    method validate (line 433) | def validate(self, attrs):
    method create (line 445) | def create(self, validated_data):
  class HostAgentRestartSerializer (line 476) | class HostAgentRestartSerializer(HostIdsSerializer):
    method create (line 479) | def create(self, validated_data):
  class HostBatchValidateSerializer (line 501) | class HostBatchValidateSerializer(Serializer):
    method host_info_validate (line 511) | def host_info_validate(self, host_data):
    method validate (line 527) | def validate(self, attrs):
  class HostBatchImportSerializer (line 574) | class HostBatchImportSerializer(Serializer):
  class HostInitSerializer (line 585) | class HostInitSerializer(HostIdsSerializer):
    method create (line 588) | def create(self, validated_data):
  class HostsAgentStatusSerializer (line 600) | class HostsAgentStatusSerializer(Serializer):
  class HostReinstallSerializer (line 611) | class HostReinstallSerializer(HostIdsSerializer):
    method create (line 614) | def create(self, validated_data):
  class MonitorReinstallSerializer (line 626) | class MonitorReinstallSerializer(HostIdsSerializer):
    method create (line 629) | def create(self, validated_data):

FILE: omp_server/hosts/tasks.py
  function deploy_monitor_agent (line 47) | def deploy_monitor_agent(host_obj, salt_flag=True):
  function real_deploy_agent (line 78) | def real_deploy_agent(host_obj, need_monitor=True):
  function deploy_agent (line 119) | def deploy_agent(host_id, need_monitor=True):
  function real_host_agent_restart (line 145) | def real_host_agent_restart(host_obj):
  function host_agent_restart (line 185) | def host_agent_restart(host_id):
  function real_init_host (line 203) | def real_init_host(host_obj):
  function init_host (line 252) | def init_host(host_id):
  function insert_host_celery_task (line 271) | def insert_host_celery_task(host_id, init=False):
  function write_host_log (line 333) | def write_host_log(host_queryset, status, result, username):
  function maintenance (line 345) | def maintenance(host_obj, entry, username):
  function reinstall_monitor_celery_task (line 370) | def reinstall_monitor_celery_task(host_id, username):
  class UninstallHosts (line 414) | class UninstallHosts(object):
    method __init__ (line 415) | def __init__(self, all_host):
    method cmd (line 420) | def cmd(command):
    method delete_salt_key (line 430) | def delete_salt_key(self, key_list):
    method del_single_agent (line 445) | def del_single_agent(obj):
    method execute_uninstall (line 515) | def execute_uninstall(host_obj_list, thread_name_prefix, function, max...
    method delete_all_omp_agent (line 539) | def delete_all_omp_agent(self):
  function delete_hosts (line 568) | def delete_hosts(host_ids):

FILE: omp_server/hosts/views.py
  class HostListView (line 40) | class HostListView(GenericViewSet, ListModelMixin, CreateModelMixin):
    method list (line 63) | def list(self, request, *args, **kwargs):
  class HostReinstallView (line 107) | class HostReinstallView(GenericViewSet, CreateModelMixin):
  class MonitorReinstallView (line 118) | class MonitorReinstallView(GenericViewSet, CreateModelMixin):
  class HostUninstallView (line 129) | class HostUninstallView(GenericViewSet, CreateModelMixin):
  class HostDetailView (line 140) | class HostDetailView(GenericViewSet, RetrieveModelMixin):
  class HostUpdateView (line 151) | class HostUpdateView(GenericViewSet, UpdateModelMixin):
  class HostFieldCheckView (line 165) | class HostFieldCheckView(GenericViewSet, CreateModelMixin):
    method create (line 175) | def create(self, request, *args, **kwargs):
  class IpListView (line 180) | class IpListView(GenericViewSet, ListModelMixin):
    method list (line 190) | def list(self, request, *args, **kwargs):
  class HostMaintenanceView (line 194) | class HostMaintenanceView(GenericViewSet, CreateModelMixin):
  class HostAgentRestartView (line 205) | class HostAgentRestartView(GenericViewSet, CreateModelMixin):
  class HostOperateLogView (line 216) | class HostOperateLogView(GenericViewSet, ListModelMixin):
  class HostBatchValidateView (line 230) | class HostBatchValidateView(BaseDownLoadTemplateView, CreateModelMixin):
    method list (line 244) | def list(self, request, *args, **kwargs):
    method create (line 249) | def create(self, request, *args, **kwargs):
  class HostBatchImportView (line 270) | class HostBatchImportView(GenericViewSet, CreateModelMixin):
    method create (line 279) | def create(self, request, *args, **kwargs):
  class HostInitView (line 335) | class HostInitView(BaseDownLoadTemplateView, CreateModelMixin):
    method list (line 347) | def list(self, request, *args, **kwargs):
  class HostsAgentStatusView (line 353) | class HostsAgentStatusView(GenericViewSet, CreateModelMixin):
    method create (line 363) | def create(self, request, *args, **kwargs):

FILE: omp_server/inspection/apps.py
  class InspectionConfig (line 4) | class InspectionConfig(AppConfig):

FILE: omp_server/inspection/filters.py
  class InspectionHistoryFilter (line 12) | class InspectionHistoryFilter(FilterSet):
    class Meta (line 27) | class Meta:
  class InspectionCrontabFilter (line 32) | class InspectionCrontabFilter(FilterSet):
    class Meta (line 38) | class Meta:
  class InspectionReportFilter (line 43) | class InspectionReportFilter(FilterSet):
    class Meta (line 48) | class Meta:

FILE: omp_server/inspection/get_prometheus_risk_data.py
  function get_risk_data (line 10) | def get_risk_data(handle, hosts, services):

FILE: omp_server/inspection/get_service_topology.py
  function get_topology_data (line 10) | def get_topology_data():

FILE: omp_server/inspection/inspection_utils.py
  function send_email (line 13) | def send_email(inspection, emails):
  function create_send_inspection_html (line 82) | def create_send_inspection_html(inspection):
  function send_report_email (line 118) | def send_report_email(inspection_module, inspection_id, emails):

FILE: omp_server/inspection/joint_json_report.py
  function joint_json_data (line 8) | def joint_json_data(handle, _r, _h):

FILE: omp_server/inspection/serializers.py
  class InspectionHistorySerializer (line 11) | class InspectionHistorySerializer(ModelSerializer):
    class Meta (line 14) | class Meta:
  class InspectionCrontabSerializer (line 20) | class InspectionCrontabSerializer(ModelSerializer):
    class Meta (line 23) | class Meta:
  class InspectionReportSerializer (line 29) | class InspectionReportSerializer(ModelSerializer):
    class Meta (line 32) | class Meta:

FILE: omp_server/inspection/tasks.py
  function get_hosts_data (line 30) | def get_hosts_data(env, hosts):
  function get_prometheus_data (line 58) | def get_prometheus_data(env_id, hosts, services, history_id, report_id, ...
  function inspection_crontab (line 154) | def inspection_crontab(**kwargs):

FILE: omp_server/inspection/views.py
  class InspectionServiceView (line 36) | class InspectionServiceView(ListModelMixin, GenericViewSet):
    method list (line 41) | def list(self, request, *args, **kwargs):
  class InspectionHistoryView (line 53) | class InspectionHistoryView(ListModelMixin, GenericViewSet, CreateModelM...
    method list (line 69) | def list(self, request, *args, **kwargs):
    method joint_inspection_name (line 99) | def joint_inspection_name(data_dict):
    method create (line 109) | def create(self, request, *args, **kwargs):
  class InspectionCrontabView (line 131) | class InspectionCrontabView(RetrieveModelMixin, ListModelMixin, GenericV...
    method transfer_week (line 151) | def transfer_week(request):
    method create (line 165) | def create(self, request, *args, **kwargs):
    method update (line 195) | def update(self, request, *args, **kwargs):
  class InspectionReportView (line 236) | class InspectionReportView(GenericViewSet, RetrieveModelMixin):
    method retrieve (line 247) | def retrieve(self, request, *args, **kwargs):
  class InspectionSendEmailSettingView (line 260) | class InspectionSendEmailSettingView(GenericViewSet, ListModelMixin, Cre...
    method list (line 269) | def list(self, request, *args, **kwargs):
    method create (line 283) | def create(self, request, *args, **kwargs):
  class InspectionSendEmailAPIView (line 307) | class InspectionSendEmailAPIView(GenericViewSet, CreateModelMixin):
    method create (line 314) | def create(self, request, *args, **kwargs):

FILE: omp_server/manage.py
  function main (line 7) | def main():

FILE: omp_server/promemonitor/alert_util.py
  function get_service_type (line 13) | def get_service_type(ip, service_name):
  function get_monitor_url (line 26) | def get_monitor_url(ele):
  function get_log_url (line 35) | def get_log_url(ele):
  function utc_to_local (line 44) | def utc_to_local(utc_time_str, utc_format='%Y-%m-%dT%H:%M:%SZ'):
  class AlertAnalysis (line 67) | class AlertAnalysis:
    method __init__ (line 69) | def __init__(self, item):
    method _get (line 102) | def _get(items, key):
    method node_exporter (line 113) | def node_exporter(self):
    method exporter (line 122) | def exporter(self):
    method get_alert_time (line 162) | def get_alert_time(self):
    method analysis_labels (line 168) | def analysis_labels(self):
    method analysis_annotations (line 214) | def analysis_annotations(self):
    method __call__ (line 223) | def __call__(self, env_id=1, *args, **kwargs):

FILE: omp_server/promemonitor/alertmanager.py
  class Alertmanager (line 14) | class Alertmanager:
    method __init__ (line 19) | def __init__(self):
    method get_alertmanager_config (line 28) | def get_alertmanager_config():
    method format_time (line 41) | def format_time(_time):
    method add_setting (line 53) | def add_setting(self, value, name="env", start_time=None, ends_time=No...
    method delete_setting (line 94) | def delete_setting(self, silence_id):
    method set_maintain_by_host_list (line 112) | def set_maintain_by_host_list(self, host_list):
    method set_maintain_by_env_name (line 131) | def set_maintain_by_env_name(self, env_name):
    method revoke_maintain_by_host_list (line 142) | def revoke_maintain_by_host_list(self, host_list):
    method revoke_maintain_by_env_name (line 164) | def revoke_maintain_by_env_name(self, env_name):

FILE: omp_server/promemonitor/apps.py
  class PromemonitorConfig (line 4) | class PromemonitorConfig(AppConfig):

FILE: omp_server/promemonitor/custom_script_serializers.py
  class CustomScriptSerializer (line 13) | class CustomScriptSerializer(ModelSerializer):
    class Meta (line 17) | class Meta:
    method get_bound_hosts_num (line 21) | def get_bound_hosts_num(self, obj):  # NOQA

FILE: omp_server/promemonitor/custom_script_views.py
  class CustomScriptViewSet (line 32) | class CustomScriptViewSet(GenericViewSet, ListModelMixin, CreateModelMix...
    method list (line 57) | def list(self, request, *args, **kwargs):
    method create (line 71) | def create(self, request, *args, **kwargs):
    method update (line 139) | def update(self, request, *args, **kwargs):
    method destroy (line 211) | def destroy(self, request, *args, **kwargs):
  class CustomScriptJobInfoView (line 254) | class CustomScriptJobInfoView(GenericViewSet, ListModelMixin):
    method list (line 261) | def list(self, request, *args, **kwargs):

FILE: omp_server/promemonitor/grafana_url.py
  class CurlPrometheus (line 14) | class CurlPrometheus(object):
    method curl_prometheus (line 16) | def curl_prometheus():
  function utc_local (line 35) | def utc_local(utc_time_str, utc_format='%Y-%m-%dT%H:%M:%SZ'):
  function get_item_type (line 58) | def get_item_type(item, database_list, service_list, component_list):
  function explain_prometheus (line 87) | def explain_prometheus(params):
  function explain_filter (line 155) | def explain_filter(prometheus_json, params):
  function explain_url (line 173) | def explain_url(explain_info, is_service=None, is_host=None):

FILE: omp_server/promemonitor/grafana_views.py
  function grafana_proxy (line 29) | def grafana_proxy(request, url, requests_args=None):
  function grafana_proxy_view (line 98) | def grafana_proxy_view(request, path):

FILE: omp_server/promemonitor/promemonitor_filters.py
  class AlertFilter (line 13) | class AlertFilter(FilterSet):
    class Meta (line 24) | class Meta:
  class QuotaFilter (line 32) | class QuotaFilter(FilterSet):
    class Meta (line 41) | class Meta:
  class MyTimeFilter (line 48) | class MyTimeFilter(BaseFilterBackend):
    method filter_queryset (line 50) | def filter_queryset(self, request, queryset, view):
  class CustomScriptFilter (line 63) | class CustomScriptFilter(FilterSet):
    class Meta (line 68) | class Meta:

FILE: omp_server/promemonitor/promemonitor_serializers.py
  class MonitorUrlListSerializer (line 23) | class MonitorUrlListSerializer(ListSerializer):
    method update (line 25) | def update(self, instance, validated_data):
    method to_internal_value (line 28) | def to_internal_value(self, data):
    method validate (line 31) | def validate(self, data):
    method create (line 57) | def create(self, validated_data):
  class MonitorUrlSerializer (line 62) | class MonitorUrlSerializer(ModelSerializer):
    class Meta (line 84) | class Meta:
    method validate_name (line 89) | def validate_name(self, name):
    method validate_monitor_url (line 98) | def validate_monitor_url(self, monitor_url):
  class ListAlertSerializer (line 104) | class ListAlertSerializer(ModelSerializer):
    class Meta (line 105) | class Meta:
  class UpdateAlertSerializer (line 110) | class UpdateAlertSerializer(Serializer):
    method create (line 131) | def create(self, validated_data):
    method update (line 136) | def update(self, instance, validated_data):
  class MaintainSerializer (line 140) | class MaintainSerializer(ModelSerializer):
    method validate (line 157) | def validate(self, attrs):
    method create (line 161) | def create(self, validated_data):
    class Meta (line 187) | class Meta:
  class ReceiveAlertSerializer (line 192) | class ReceiveAlertSerializer(Serializer):
    method update (line 209) | def update(self, instance, validated_data):
    method create (line 212) | def create(self, validated_data):
  class MonitorAgentRestartSerializer (line 256) | class MonitorAgentRestartSerializer(HostIdsSerializer):
    method update (line 259) | def update(self, instance, validated_data):
    method create (line 262) | def create(self, validated_data):
  class RuleSerializer (line 284) | class RuleSerializer(ModelSerializer):
    class Meta (line 289) | class Meta:
  class QuotaSerializer (line 297) | class QuotaSerializer(ModelSerializer):
    class Meta (line 302) | class Meta:

FILE: omp_server/promemonitor/prometheus.py
  class Prometheus (line 13) | class Prometheus:
    method __init__ (line 19) | def __init__(self):
    method get_prometheus_config (line 27) | def get_prometheus_config():
    method get_host_threshold (line 39) | def get_host_threshold(env_id=1,**kwargs):
    method get_host_metric_status (line 121) | def get_host_metric_status(self, metric, metric_value, **kwargs):
    method get_host_cpu_usage (line 133) | def get_host_cpu_usage(self, host_list):
    method get_host_mem_usage (line 174) | def get_host_mem_usage(self, host_list):
    method get_host_root_disk_usage (line 215) | def get_host_root_disk_usage(self, host_list):
    method get_host_data_disk_usage (line 258) | def get_host_data_disk_usage(self, host_list):
    method get_host_info (line 306) | def get_host_info(self, host_list):
    method get_all_service_status (line 325) | def get_all_service_status(self):
    method get_all_host_targets (line 353) | def get_all_host_targets(self):
    method get_all_service_targets (line 371) | def get_all_service_targets(self):
    method get_service_threshold (line 391) | def get_service_threshold(env_id=1):
    method get_service_metric_status (line 420) | def get_service_metric_status(self, metric, metric_value):
    method get_service_cpu_usage (line 432) | def get_service_cpu_usage(self, service_list):
    method get_service_mem_usage (line 499) | def get_service_mem_usage(self, service_list):
    method get_service_info (line 578) | def get_service_info(self, service_list):
    method get_quota_res (line 591) | def get_quota_res(self,quota):
  class UpdatePrometheusRule (line 611) | class UpdatePrometheusRule(object):

FILE: omp_server/promemonitor/prometheus_utils.py
  class PrometheusUtils (line 59) | class PrometheusUtils(object):
    method __init__ (line 62) | def __init__(self):
    method replace_placeholder (line 93) | def replace_placeholder(path, placeholder_list):
    method json_distinct (line 112) | def json_distinct(iterable_lst):
    method get_dic_from_yaml (line 125) | def get_dic_from_yaml(file_path):
    method write_dic_to_yaml (line 137) | def write_dic_to_yaml(dic, file_path):
    method get_expr (line 149) | def get_expr(num, env, data_path):
    method get_service_port (line 170) | def get_service_port(service_name):
    method make_data_node_rule (line 174) | def make_data_node_rule(self, level, data_path, env="default"):
    method update_node_data_rule (line 213) | def update_node_data_rule(self, data_path, env="default"):
    method add_rules (line 261) | def add_rules(self, rule_type, env="default"):
    method delete_rules (line 322) | def delete_rules(self, rule_type, env="default"):
    method add_node (line 345) | def add_node(self, nodes_data):
    method delete_node (line 398) | def delete_node(self, nodes_data):
    method update_agent_service (line 427) | def update_agent_service(self, dest_ip, action, services_data):
    method add_service (line 519) | def add_service(self, service_data):
    method delete_service (line 604) | def delete_service(self, service_data):
    method update_host_threshold (line 649) | def update_host_threshold(self, env="default", env_id=1):
    method gen_one_rule (line 704) | def gen_one_rule(self, **kwargs):  # NOQA
    method get_hash_value (line 730) | def get_hash_value(self, expr, severity):  # NOQA
    method add_data_disk_rules (line 735) | def add_data_disk_rules(self, data_path, env="default"):
    method update_rule_file (line 783) | def update_rule_file(self, add_data=None, add=False, update=False, del...
    method reload_prometheus (line 826) | def reload_prometheus(self):

FILE: omp_server/promemonitor/tasks.py
  function real_monitor_agent_restart (line 28) | def real_monitor_agent_restart(host_obj):
  function monitor_agent_restart (line 62) | def monitor_agent_restart(host_id):

FILE: omp_server/promemonitor/views.py
  class MonitorUrlViewSet (line 49) | class MonitorUrlViewSet(ListModelMixin, CreateModelMixin, GenericViewSet):
    method get_serializer (line 65) | def get_serializer(self, *args, **kwargs):
    method multiple_update (line 76) | def multiple_update(self, request, *args, **kwargs):
  class GrafanaUrlViewSet (line 89) | class GrafanaUrlViewSet(ListModelMixin, GenericViewSet):
    method list (line 96) | def list(self, request, *args, **kwargs):
  class ListAlertViewSet (line 110) | class ListAlertViewSet(ListModelMixin, GenericViewSet):
  class UpdateAlertViewSet (line 126) | class UpdateAlertViewSet(CreateModelMixin, GenericViewSet):
  class MaintainViewSet (line 135) | class MaintainViewSet(GenericViewSet, CreateModelMixin, ListModelMixin):
  class ReceiveAlertViewSet (line 147) | class ReceiveAlertViewSet(GenericViewSet, CreateModelMixin):
  class MonitorAgentRestartView (line 160) | class MonitorAgentRestartView(GenericViewSet, CreateModelMixin):
  class InstanceNameListView (line 171) | class InstanceNameListView(GenericViewSet, ListModelMixin):
    method list (line 178) | def list(self, request, *args, **kwargs):
  class InstrumentPanelView (line 188) | class InstrumentPanelView(GenericViewSet, ListModelMixin):
    method get_prometheus_alerts (line 196) | def get_prometheus_alerts():
    method get_exc_serializer_info (line 214) | def get_exc_serializer_info(self):
    method list (line 467) | def list(self, request, *args, **kwargs):
  class GetSendEmailConfig (line 472) | class GetSendEmailConfig(GenericViewSet, ListModelMixin):
    method list (line 478) | def list(self, request, *args, **kwargs):
  class UpdateSendEmailConfig (line 485) | class UpdateSendEmailConfig(GenericViewSet, CreateModelMixin):
    method create (line 493) | def create(self, request, *args, **kwargs):
  class GetSendAlertSettingView (line 531) | class GetSendAlertSettingView(GenericViewSet, ListModelMixin):
    method list (line 537) | def list(self, request, *args, **kwargs):
  class UpdateSendAlertSettingView (line 552) | class UpdateSendAlertSettingView(GenericViewSet, CreateModelMixin):
    method create (line 558) | def create(self, request, *args, **kwargs):
  class HostThresholdView (line 586) | class HostThresholdView(GenericViewSet, ListModelMixin, CreateModelMixin):
    method list (line 596) | def list(self, request, *args, **kwargs):
    method create (line 623) | def create(self, request, *args, **kwargs):
  class ServiceThresholdView (line 678) | class ServiceThresholdView(GenericViewSet, ListModelMixin, CreateModelMi...
    method list (line 688) | def list(self, request, *args, **kwargs):
    method create (line 714) | def create(self, request, *args, **kwargs):
  class CustomThresholdView (line 757) | class CustomThresholdView(GenericViewSet, ListModelMixin, CreateModelMix...
    method list (line 767) | def list(self, request, *args, **kwargs):
    method valid_kafka_kafka_consumergroup_lag (line 805) | def valid_kafka_kafka_consumergroup_lag(self, value):  # NOQA
    method create (line 810) | def create(self, request, *args, **kwargs):
  class QuotaView (line 871) | class QuotaView(ListModelMixin, GenericViewSet, CreateModelMixin, Destro...
    method create (line 888) | def create(self, request, *args, **kwargs):
    method delete (line 996) | def delete(self, request, *args, **kwargs):
  class BuiltinsRuleView (line 1016) | class BuiltinsRuleView(GenericViewSet, ListModelMixin):
    method list (line 1021) | def list(self, request, *args, **kwargs):
  class PromSqlTestView (line 1033) | class PromSqlTestView(GenericViewSet, CreateModelMixin):
    method create (line 1037) | def create(self, request, *args, **kwargs):
  class BatchUpdateRuleView (line 1045) | class BatchUpdateRuleView(GenericViewSet, CreateModelMixin):
    method create (line 1053) | def create(self, request, *args, **kwargs):

FILE: omp_server/service_upgrade/apps.py
  class ServiceUpgradeConfig (line 4) | class ServiceUpgradeConfig(AppConfig):

FILE: omp_server/service_upgrade/filters.py
  class RollBackHistoryFilter (line 4) | class RollBackHistoryFilter(BaseFilterBackend):
    method filter_queryset (line 6) | def filter_queryset(self, request, queryset, view):

FILE: omp_server/service_upgrade/handler/base.py
  function get_install_detail (line 14) | def get_install_detail(detail, service, operation_uuid):
  function load_upgrade_detail (line 52) | def load_upgrade_detail(upgrade_detail, operation_uuid):
  function load_rollback_detail (line 68) | def load_rollback_detail(rollback_detail, operation_uuid):
  class BaseHandler (line 85) | class BaseHandler:
    method __init__ (line 90) | def __init__(self, salt_client):
    method _log (line 93) | def _log(self, message, level="info"):
    method success_handler (line 107) | def success_handler(self):
    method fail_handler (line 118) | def fail_handler(self):
    method valid_args (line 126) | def valid_args(cls, detail_args, detail):
    method __call__ (line 136) | def __call__(self, operation_args, *args, **kwargs):
  class StartOperationMixin (line 165) | class StartOperationMixin:
    method handler (line 167) | def handler(self):
    method __call__ (line 171) | def __call__(self, operation_args, *args, **kwargs):
  class StopServiceMixin (line 181) | class StopServiceMixin:
    method stop_service (line 185) | def stop_service(self, service):
  class StartServiceMixin (line 206) | class StartServiceMixin:
    method start_service (line 210) | def start_service(self, service):
  function handler_pipeline (line 227) | def handler_pipeline(handlers, objs):

FILE: omp_server/service_upgrade/handler/rollback_handler.py
  class RollbackBaseHandler (line 18) | class RollbackBaseHandler(BaseHandler):
    method write_db (line 22) | def write_db(self, result=False):
    method sync_relation_details (line 35) | def sync_relation_details(self):
    method handler (line 47) | def handler(self):
    method detail_class (line 51) | def detail_class(self):
    method union_server (line 55) | def union_server(self):
  class StartRollbackHandler (line 59) | class StartRollbackHandler(StartOperationMixin, RollbackBaseHandler):
    method set_service_state (line 64) | def set_service_state(self):
  class RollBackStopServiceHandler (line 80) | class RollBackStopServiceHandler(RollbackBaseHandler):
    method stop_service (line 85) | def stop_service(self, service):
    method handler (line 99) | def handler(self):
  class RollBackServiceHandler (line 113) | class RollBackServiceHandler(RollbackBaseHandler):
    method handler (line 117) | def handler(self):
  class RollBackStartServiceHandler (line 151) | class RollBackStartServiceHandler(StartServiceMixin, RollbackBaseHandler):
    method sync_relation_details (line 154) | def sync_relation_details(self):
    method write_db (line 171) | def write_db(self, result=False):
    method handler (line 189) | def handler(self):

FILE: omp_server/service_upgrade/handler/upgrade_handler.py
  class UpgradeBaseHandler (line 18) | class UpgradeBaseHandler(BaseHandler):
    method write_db (line 22) | def write_db(self, result=False):
    method sync_relation_details (line 35) | def sync_relation_details(self):
    method handler (line 47) | def handler(self):
    method detail_class (line 51) | def detail_class(self):
    method union_server (line 55) | def union_server(self):
  class StartUpgradeHandler (line 59) | class StartUpgradeHandler(StartOperationMixin, UpgradeBaseHandler):
    method set_service_state (line 63) | def set_service_state(self):
  class StopServiceHandler (line 79) | class StopServiceHandler(StopServiceMixin, UpgradeBaseHandler):
    method handler (line 81) | def handler(self):
  class BackupServiceHandler (line 95) | class BackupServiceHandler(UpgradeBaseHandler):
    method do_backup (line 98) | def do_backup(self, backup_package):
    method handler (line 119) | def handler(self):
  class SendPackageHandler (line 127) | class SendPackageHandler(UpgradeBaseHandler):
    method handler (line 130) | def handler(self):
  class UnzipPackageHandler (line 151) | class UnzipPackageHandler(UpgradeBaseHandler):
    method handler (line 154) | def handler(self):
  class UpgradeServiceHandler (line 171) | class UpgradeServiceHandler(UpgradeBaseHandler):
    method handler (line 174) | def handler(self):
  class StartServiceHandler (line 201) | class StartServiceHandler(StartServiceMixin, UpgradeBaseHandler):
    method sync_relation_details (line 203) | def sync_relation_details(self):
    method write_db (line 217) | def write_db(self, result=False):
    method fail_handler (line 230) | def fail_handler(self):
    method handler (line 237) | def handler(self):

FILE: omp_server/service_upgrade/serializers.py
  class UpgradeHistorySerializer (line 10) | class UpgradeHistorySerializer(serializers.ModelSerializer):
    method get_service_count (line 16) | def get_service_count(self, obj):
    class Meta (line 19) | class Meta:
  class RollbackHistorySerializer (line 25) | class RollbackHistorySerializer(serializers.ModelSerializer):
    method get_service_count (line 30) | def get_service_count(self, obj):
    class Meta (line 33) | class Meta:
  class UpgradeDetailSerializer (line 39) | class UpgradeDetailSerializer(serializers.ModelSerializer):
    class Meta (line 46) | class Meta:
  class RollbackDetailSerializer (line 52) | class RollbackDetailSerializer(serializers.ModelSerializer):
    class Meta (line 60) | class Meta:
  class UpgradeHistoryDetailSerializer (line 66) | class UpgradeHistoryDetailSerializer(serializers.ModelSerializer):
    method get_upgrade_details (line 73) | def get_upgrade_details(self, obj, key):
    method get_pre_upgrade (line 97) | def get_pre_upgrade(self, obj):
    method get_upgrade_detail (line 115) | def get_upgrade_detail(self, obj):
    method get_can_rollback (line 140) | def get_can_rollback(self, obj):
    method get_success_count (line 143) | def get_success_count(self, obj):
    method get_all_count (line 146) | def get_all_count(self, obj):
    class Meta (line 149) | class Meta:
  class RollbackHistoryDetailSerializer (line 156) | class RollbackHistoryDetailSerializer(serializers.ModelSerializer):
    method get_rollback_details (line 162) | def get_rollback_details(self, obj, key):
    method get_rollback_detail (line 186) | def get_rollback_detail(self, obj):
    method get_success_count (line 208) | def get_success_count(self, obj):
    method get_all_count (line 211) | def get_all_count(self, obj):
    class Meta (line 214) | class Meta:
  class UpgradeTryAgainSerializer (line 220) | class UpgradeTryAgainSerializer(serializers.ModelSerializer):
    class Meta (line 224) | class Meta:
    method validate (line 228) | def validate(self, attrs):
  class RollbackTryAgainSerializer (line 244) | class RollbackTryAgainSerializer(serializers.ModelSerializer):
    class Meta (line 247) | class Meta:
    method validate (line 251) | def validate(self, attrs):
  class ApplicationHubSerializer (line 259) | class ApplicationHubSerializer(serializers.ModelSerializer):
    class Meta (line 262) | class Meta:
  class ServiceSerializer (line 267) | class ServiceSerializer(serializers.ModelSerializer):
    class Meta (line 274) | class Meta:
  class RollbackListSerializer (line 280) | class RollbackListSerializer(serializers.ModelSerializer):
    class Meta (line 288) | class Meta:

FILE: omp_server/service_upgrade/tasks.py
  function get_service_order (line 22) | def get_service_order():
  function computer_operation_sorted (line 31) | def computer_operation_sorted(details):
  function set_alert_maintain (line 60) | def set_alert_maintain(env_name):
  function update_data_json (line 72) | def update_data_json(operation_uuid, details):
  function load_upgrade_service (line 86) | def load_upgrade_service(history):
  function load_rollback_service (line 95) | def load_rollback_service(history):
  function update_product_version (line 104) | def update_product_version(app_ids):
  function upgrade_service (line 125) | def upgrade_service(upgrade_history_id):
  function rollback_service (line 199) | def rollback_service(rollback_history_id):

FILE: omp_server/service_upgrade/update_data_json.py
  class DataJsonUpdate (line 10) | class DataJsonUpdate(object):
    method __init__ (line 13) | def __init__(self, operation_uuid):
    method get_ser_install_args (line 22) | def get_ser_install_args(self, obj, app_install_args=None):
    method parse_single_service (line 55) | def parse_single_service(self, service, tag_app=None):
    method make_data_json (line 90) | def make_data_json(self, json_lst):
    method decompose_detail (line 107) | def decompose_detail(self, details):
    method load_json_lst (line 119) | def load_json_lst(self, details):
    method send_data_json_target (line 134) | def send_data_json_target(self, salt_obj, target_ip):
    method send_data_json_all (line 144) | def send_data_json_all(self):
    method create_json_file (line 161) | def create_json_file(self, details=None):

FILE: omp_server/service_upgrade/views.py
  class UpgradeHistoryListAPIView (line 27) | class UpgradeHistoryListAPIView(ListAPIView):
  class UpgradeHistoryDetailAPIView (line 39) | class UpgradeHistoryDetailAPIView(RetrieveUpdateAPIView):
    method update (line 48) | def update(self, request, *args, **kwargs):
  class UpgradeChoiceAllVersionListAPIView (line 57) | class UpgradeChoiceAllVersionListAPIView(GenericAPIView):
    method get_service_info (line 66) | def get_service_info(self, services_data):
    method get (line 83) | def get(self, requests):
  class UpgradeChoiceMaxVersionListAPIView (line 130) | class UpgradeChoiceMaxVersionListAPIView(UpgradeChoiceAllVersionListAPIV...
    method get_service_max_app (line 134) | def get_service_max_app(self, apps):
    method get (line 142) | def get(self, requests):
  class DoUpgradeAPIView (line 179) | class DoUpgradeAPIView(GenericAPIView):
    method valid_can_upgrade (line 182) | def valid_can_upgrade(self, data):
    method post (line 227) | def post(self, requests):
  class RollbackHistoryListAPIView (line 291) | class RollbackHistoryListAPIView(ListAPIView):
  class RollbackHistoryDetailAPIView (line 302) | class RollbackHistoryDetailAPIView(RetrieveUpdateAPIView):
    method update (line 310) | def update(self, request, *args, **kwargs):
  class RollbackChoiceListAPIView (line 318) | class RollbackChoiceListAPIView(GenericAPIView):
    method get (line 329) | def get(self, requests):
  class DoRollbackAPIView (line 352) | class DoRollbackAPIView(GenericAPIView):
    method post (line 355) | def post(self, requests):

FILE: omp_server/services/app_check/conf_check.py
  class ConfCheck (line 21) | class ConfCheck:
    method __init__ (line 23) | def __init__(self, app_data):
    method _get_service_k_v (line 44) | def _get_service_k_v():
    method _get_cluster_ip (line 54) | def _get_cluster_ip():
    method explain_json (line 66) | def explain_json(text):
    method fix_service (line 71) | def fix_service(self):
    method fix_dependence (line 102) | def fix_dependence(self):
    method produce_cmd_and_exec (line 136) | def produce_cmd_and_exec(self, ip, agent_dir, install_args, app):
    method get_dependence (line 177) | def get_dependence(self, app, ip):
    method explain_common_res (line 333) | def explain_common_res(self, ips_ls, app, version, install_args):
    method append_error (line 364) | def append_error(self, app, message, ip_ls=None):
    method check_component_cmd (line 377) | def check_component_cmd(self, install_args, app):
    method run (line 413) | def run(self):

FILE: omp_server/services/app_check/manage_ser_exec.py
  class ManagerService (line 20) | class ManagerService:
    method __init__ (line 21) | def __init__(self, info, is_extend=False):
    method _get_cluster_ip (line 33) | def _get_cluster_ip():
    method check_redis (line 48) | def check_redis(self):
    method check_service (line 66) | def check_service(self):
    method update_port (line 84) | def update_port(app_obj, app_data):
    method update_service_controllers (line 92) | def update_service_controllers(app_obj, app_data):
    method update_install_args (line 103) | def update_install_args(app_obj, install_detail_args):
    method create_install_detail (line 111) | def create_install_detail(self, main_obj, install_detail_args, ser_obj...
    method get_service_dependence (line 150) | def get_service_dependence(self, dependence, ip):
    method get_or_create_service_connect_info (line 175) | def get_or_create_service_connect_info(app_name, app_obj):
    method create_cluster_new (line 195) | def create_cluster_new(self, app_obj, app_data, app_name, real_ip_ls):
    method create_cluster (line 224) | def create_cluster(self, app_obj, app_data, app_name, real_ip_ls):
    method get_or_create_env (line 249) | def get_or_create_env(self):
    method create_database_one (line 257) | def create_database_one(self, data, main_obj):
    method create_database_all (line 292) | def create_database_all(self):
    method run (line 317) | def run(self):

FILE: omp_server/services/apps.py
  class ServicesConfig (line 4) | class ServicesConfig(AppConfig):

FILE: omp_server/services/permission.py
  class GetDataJsonAuthenticated (line 5) | class GetDataJsonAuthenticated(BasePermission):
    method has_permission (line 10) | def has_permission(self, request, view):

FILE: omp_server/services/self_heal_filter.py
  class SelfHealingHistoryFilter (line 8) | class SelfHealingHistoryFilter(FilterSet):
    class Meta (line 16) | class Meta:
  class SelfHealingTimeFilter (line 21) | class SelfHealingTimeFilter(BaseFilterBackend):
    method filter_queryset (line 22) | def filter_queryset(self, request, queryset, view):

FILE: omp_server/services/self_heal_serializers.py
  class SelfHealingSettingSerializer (line 12) | class SelfHealingSettingSerializer(BulkSerializerMixin, ModelSerializer):
    class Meta (line 13) | class Meta:
    method validate (line 18) | def validate(self, attrs):
  class ListSelfHealingHistorySerializer (line 31) | class ListSelfHealingHistorySerializer(ModelSerializer):
    class Meta (line 32) | class Meta:
  class UpdateSelfHealingHistorySerializer (line 37) | class UpdateSelfHealingHistorySerializer(Serializer):
    method create (line 42) | def create(self, validated_data):

FILE: omp_server/services/self_heal_util.py
  function get_service_status_direct (line 11) | def get_service_status_direct(service_obj_list):

FILE: omp_server/services/self_heal_view.py
  class SelfHealingSettingView (line 20) | class SelfHealingSettingView(GenericViewSet, ListModelMixin, CreateModel...
    method list (line 29) | def list(self, request, *args, **kwargs):
  class ListSelfHealingHistoryView (line 50) | class ListSelfHealingHistoryView(GenericViewSet, ListModelMixin):
  class UpdateSelfHealingHistoryView (line 64) | class UpdateSelfHealingHistoryView(CreateModelMixin, GenericViewSet):

FILE: omp_server/services/self_healing.py
  class SelfHealing (line 25) | class SelfHealing:
    method __init__ (line 26) | def __init__(self, instance_tp, max_healing_count):
    method merge_and_filter_ser (line 34) | def merge_and_filter_ser(self, alert_info):
    method sort_service (line 57) | def sort_service(self, alert_info):
    method exec_salt_cmd (line 79) | def exec_salt_cmd(self, ip, command, his_obj):
    method check_health (line 102) | def check_health(ip, command, his_obj, healing_log):
    method get_command (line 119) | def get_command(self, instance_name):
    method write_db (line 138) | def write_db(data, healing_count):
    method get_redis_count (line 167) | def get_redis_count(self, instance_name):
    method host (line 183) | def host(self, hosts_info):
    method service (line 205) | def service(self, service_info):
  function get_enable_health (line 229) | def get_enable_health(repairs):
  function self_healing (line 239) | def self_healing(task_id):
  function self_healing_ssh_verification (line 280) | def self_healing_ssh_verification(host_self_healing_list, sudo_check_cmd):
  function get_service_status_direct (line 320) | def get_service_status_direct(service_obj_list):

FILE: omp_server/services/services_filters.py
  class ServiceFilter (line 10) | class ServiceFilter(FilterSet):
    class Meta (line 21) | class Meta:

FILE: omp_server/services/services_serializers.py
  class ServiceStatusSerializer (line 11) | class ServiceStatusSerializer(DynamicFieldsModelSerializer):
    class Meta (line 18) | class Meta:
    method get_is_web (line 26) | def get_is_web(self, obj):
  class ServiceSerializer (line 33) | class ServiceSerializer(serializers.ModelSerializer):
    class Meta (line 49) | class Meta:
    method get_is_web (line 58) | def get_is_web(self, obj):
    method get_port (line 64) | def get_port(self, obj):
    method get_label_name (line 73) | def get_label_name(self, obj):
    method get_cluster_type (line 81) | def get_cluster_type(self, obj):
    method get_alert_count (line 89) | def get_alert_count(self, obj):
    method get_operable (line 105) | def get_operable(self, obj):
  class ServiceDetailSerializer (line 112) | class ServiceDetailSerializer(serializers.ModelSerializer):
    class Meta (line 122) | class Meta:
    method get_install_info (line 130) | def get_install_info(self, obj):
    method get_label_name (line 157) | def get_label_name(self, obj):
    method get_cluster_type (line 165) | def get_cluster_type(self, obj):
    method get_history (line 172) | def get_history(self, obj):
  class ServiceActionSerializer (line 178) | class ServiceActionSerializer(serializers.ModelSerializer):
    class Meta (line 181) | class Meta:
  class ServiceDeleteSerializer (line 187) | class ServiceDeleteSerializer(serializers.ModelSerializer):
    class Meta (line 190) | class Meta:
  class AppListSerializer (line 196) | class AppListSerializer(serializers.ModelSerializer):
    class Meta (line 197) | class Meta:

FILE: omp_server/services/tasks.py
  function delete_action (line 30) | def delete_action(service_obj):
  function get_app_dir (line 46) | def get_app_dir(service_obj):
  function delete_file (line 60) | def delete_file(service_controllers, service_obj):
  function exec_action (line 98) | def exec_action(action, instance, operation_user, del_file=False, need_s...
  function clear_db (line 207) | def clear_db(task_id):

FILE: omp_server/services/views.py
  class ServiceListView (line 40) | class ServiceListView(GenericViewSet, ListModelMixin):
    method list (line 57) | def list(self, request, *args, **kwargs):
  class ServiceDetailView (line 135) | class ServiceDetailView(GenericViewSet, RetrieveModelMixin):
  class ServiceActionView (line 146) | class ServiceActionView(GenericViewSet, CreateModelMixin):
    method create (line 155) | def create(self, request, *args, **kwargs):
  class ServiceDeleteView (line 187) | class ServiceDeleteView(GenericViewSet, CreateModelMixin):
    method create (line 196) | def create(self, request, *args, **kwargs):
  class ServiceStatusView (line 237) | class ServiceStatusView(GenericViewSet, ListModelMixin):
    method list (line 250) | def list(self, request, *args, **kwargs):
  class ServiceDataJsonView (line 295) | class ServiceDataJsonView(APIView):
    method get (line 299) | def get(self, request):
  class AppListView (line 314) | class AppListView(GenericViewSet, ListModelMixin, CreateModelMixin):
    method list (line 321) | def list(self, request, *args, **kwargs):
    method check_repeat (line 359) | def check_repeat(self, app_data):
    method check_dependence_one (line 378) | def check_dependence_one(dependence_dc, installed_ser_all):
    method check_dependence (line 389) | def check_dependence(self, dependence_dc, app_dc, app_data):
    method explain_json (line 424) | def explain_json(text):
    method gets_app_list (line 430) | def gets_app_list(cls):
    method create (line 451) | def create(self, request, *args, **kwargs):
  class AppConfCheckView (line 468) | class AppConfCheckView(GenericViewSet, CreateModelMixin):
    method create (line 473) | def create(self, request, *args, **kwargs):

FILE: omp_server/tests/base.py
  class BaseTest (line 10) | class BaseTest(TestCase):
    method setUp (line 13) | def setUp(self):
    method get (line 19) | def get(self, url, data=None):
    method post (line 25) | def post(self, url, data):
    method delete (line 32) | def delete(self, url, data=None):
    method put (line 39) | def put(self, url, data):
    method patch (line 46) | def patch(self, url, data):
    method login (line 53) | def login(self, remember=False):
    method logout (line 64) | def logout(self):
    method create_default_user (line 69) | def create_default_user():
    method create_default_env (line 83) | def create_default_env():
  class AutoLoginTest (line 91) | class AutoLoginTest(BaseTest):
    method setUp (line 94) | def setUp(self):
    method tearDown (line 98) | def tearDown(self):

FILE: omp_server/tests/mixin.py
  class HostsResourceMixin (line 15) | class HostsResourceMixin:
    method get_hosts (line 21) | def get_hosts(self, number=20, env_id=None):
    method destroy_hosts (line 59) | def destroy_hosts(self):
  class HostBatchRequestMixin (line 65) | class HostBatchRequestMixin:
    method get_host_batch_request (line 69) | def get_host_batch_request(number, row=False):
  class GrafanaMainPageResourceMixin (line 88) | class GrafanaMainPageResourceMixin:
    method get_grafana_main_pages (line 94) | def get_grafana_main_pages(self):
    method destroy_grafana_main_pages (line 107) | def destroy_grafana_main_pages(self):
  class LabelsResourceMixin (line 114) | class LabelsResourceMixin:
    method get_labels (line 119) | def get_labels(self, number=10, label_type=None):
    method destroy_labels (line 139) | def destroy_labels(self):
  class UploadPackageHistoryMixin (line 145) | class UploadPackageHistoryMixin:
    method get_upload_package_history (line 150) | def get_upload_package_history(self, number=20, is_many=True):
    method destroy_upload_package_history (line 179) | def destroy_upload_package_history(self):
  class ApplicationResourceMixin (line 185) | class ApplicationResourceMixin(LabelsResourceMixin, UploadPackageHistory...
    method _mock_install_info (line 189) | def _mock_install_info(self, index):
    method _create_application (line 207) | def _create_application(self, index, is_release, app_type, label_ls, a...
    method get_application (line 245) | def get_application(self, number=20, app_type=None, is_release=None):
    method destroy_application (line 279) | def destroy_application(self):
  class ProductResourceMixin (line 287) | class ProductResourceMixin(LabelsResourceMixin, UploadPackageHistoryMixin):
    method _create_product (line 291) | def _create_product(self, index, is_release, label_ls, pro_package, pr...
    method get_product (line 311) | def get_product(self, number=20, is_release=None):
    method destroy_product (line 344) | def destroy_product(self):
  class ClusterResourceMixin (line 351) | class ClusterResourceMixin:
    method get_cluster (line 355) | def get_cluster(self, number=5, service_name="test_service"):
    method destroy_cluster (line 374) | def destroy_cluster(self):
  class ServicesResourceMixin (line 380) | class ServicesResourceMixin(HostsResourceMixin, ClusterResourceMixin,
    method get_services (line 386) | def get_services(self, number=20, env_id=None):
    method destroy_services (line 455) | def destroy_services(self):
  class InstallHistoryResourceMixin (line 464) | class InstallHistoryResourceMixin(ServicesResourceMixin):
    method get_install_history (line 468) | def get_install_history(self, number=5):
    method destroy_install_history (line 497) | def destroy_install_history(self):

FILE: omp_server/tests/test_app_store/install_data_source.py
  function create_host (line 26) | def create_host(ip="127.0.0.1"):
  function create_product (line 48) | def create_product(pro_name="test", pro_version="1.0.0"):
  function create_service_package (line 93) | def create_service_package(pro_obj, ser_name, ser_version):
  function create_service (line 118) | def create_service(pro_obj):

FILE: omp_server/tests/test_app_store/test_app_store.py
  class LabelListTest (line 14) | class LabelListTest(AutoLoginTest, ApplicationResourceMixin):
    method setUp (line 17) | def setUp(self):
    method tearDown (line 22) | def tearDown(self):
    method test_label_list (line 26) | def test_label_list(self):
  class ComponentListTest (line 50) | class ComponentListTest(AutoLoginTest, ApplicationResourceMixin):
    method setUp (line 53) | def setUp(self):
    method tearDown (line 58) | def tearDown(self):
    method test_component_list_filter (line 62) | def test_component_list_filter(self):
    method test_component_list_order (line 102) | def test_component_list_order(self):
  class ServiceListTest (line 126) | class ServiceListTest(AutoLoginTest, ProductResourceMixin):
    method setUp (line 129) | def setUp(self):
    method tearDown (line 134) | def tearDown(self):
    method test_service_list_filter (line 138) | def test_service_list_filter(self):
    method test_service_list_order (line 164) | def test_service_list_order(self):
  class AppStoreDetailTest (line 185) | class AppStoreDetailTest(AutoLoginTest, ApplicationResourceMixin, Produc...
    method setUp (line 188) | def setUp(self):
    method test_application_detail (line 193) | def test_application_detail(self):
    method test_product_detail (line 207) | def test_product_detail(self):

FILE: omp_server/tests/test_app_store/test_app_store_install.py
  class ComponentEntranceTest (line 36) | class ComponentEntranceTest(AutoLoginTest, ApplicationResourceMixin):
    method setUp (line 37) | def setUp(self):
    method test_null_ret_success (line 42) | def test_null_ret_success(self):
    method test_normal_res (line 49) | def test_normal_res(self):
    method make_unique_app_data (line 57) | def make_unique_app_data(self, dic):  # NOQA
    method destroy_app (line 78) | def destroy_app(self):  # NOQA
    method make_base_app_1 (line 81) | def make_base_app_1(self):  # NOQA
    method make_base_app_2 (line 89) | def make_base_app_2(self):  # NOQA
    method make_base_app_3 (line 106) | def make_base_app_3(self):  # NOQA
    method make_unrelease_app (line 120) | def make_unrelease_app(self):  # NOQA
    method test_dependence_one_level (line 132) | def test_dependence_one_level(self):
    method test_dependence_two_level (line 144) | def test_dependence_two_level(self):
    method test_no_release_app_dependence (line 157) | def test_no_release_app_dependence(self):
  class ProductEntranceTest (line 172) | class ProductEntranceTest(ComponentEntranceTest, ProductResourceMixin):
    method setUp (line 174) | def setUp(self):
    method test_normal_res (line 179) | def test_normal_res(self):
    method make_pro_1 (line 189) | def make_pro_1(self):  # NOQA
    method make_pro_2 (line 226) | def make_pro_2(self):  # NOQA
    method make_pro_3 (line 243) | def make_pro_3(self):  # NOQA
    method test_pro_component_dependence (line 259) | def test_pro_component_dependence(self):
    method test_pro_pro_dependence (line 264) | def test_pro_pro_dependence(self):
  function create_host (line 273) | def create_host():
  function create_base_app (line 308) | def create_base_app():
  class ExecuteInstallTest (line 384) | class ExecuteInstallTest(TransactionTestCase):
    method setUp (line 385) | def setUp(self):
    method test_main_success (line 433) | def test_main_success(self, *args, **kwargs):
    method test_failed_path_exist (line 451) | def test_failed_path_exist(self, *args, **kwargs):
  class InstallHistoryTest (line 462) | class InstallHistoryTest(ExecuteInstallTest):
    method setUp (line 463) | def setUp(self):
    method test_success (line 468) | def test_success(self):

FILE: omp_server/tests/test_app_store/test_app_store_upload.py
  class PackageUploadTest (line 161) | class PackageUploadTest(AutoLoginTest):
    method setUp (line 163) | def setUp(self):
    method test_app_store_upload (line 194) | def test_app_store_upload(self, isfile, listdir, explain, exists, mkdi...
    method test_app_store_upload_md5 (line 222) | def test_app_store_upload_md5(self, local_cmd):
    method test_app_store_upload_tar (line 241) | def test_app_store_upload_tar(self, mkdir, local_cmd):
    method test_app_store_upload_file_check (line 270) | def test_app_store_upload_file_check(self, mkdir, exists, local_cmd):
    method test_app_store_upload_file_service (line 316) | def test_app_store_upload_file_service(self, mkdir, isfile, listdir, e...
    method test_app_store_upload_file_md5 (line 366) | def test_app_store_upload_file_md5(self, mkdir, isfile, listdir, expla...
    method test_app_store_explain_service (line 392) | def test_app_store_explain_service(self, with_open):
    method test_app_store_explain_component (line 403) | def test_app_store_explain_component(self, with_open):
    method test_app_store_explain_product (line 414) | def test_app_store_explain_product(self, with_open):
  class SimulationRedis (line 425) | class SimulationRedis(object):
    method exists (line 426) | def exists(self, key):
    method lpush (line 429) | def lpush(self, key, *args):
    method expire (line 432) | def expire(self, key, expire):
    method lindex (line 435) | def lindex(self, key, index):
  class PackagePublishTest (line 469) | class PackagePublishTest(AutoLoginTest):
    method setUp (line 471) | def setUp(self):
    method test_app_store_publish (line 508) | def test_app_store_publish(self, isfile, local_cmd, exe_clear, with_op...
    method test_app_store_publish_back_true (line 538) | def test_app_store_publish_back_true(self, publish, redis):
    method test_app_store_publish_back (line 552) | def test_app_store_publish_back(self, redis, exe_clear):
    method test_app_store_publish_api (line 566) | def test_app_store_publish_api(self, delay):
    method test_app_store_publish_clear (line 597) | def test_app_store_publish_clear(self, local_cmd):
    method test_app_store_scan (line 622) | def test_app_store_scan(self, bak, front, isfile, listdir, redis):

FILE: omp_server/tests/test_app_store/test_execute_package_scan.py
  class ExecutePackageScanTest (line 21) | class ExecutePackageScanTest(AutoLoginTest):
    method setUp (line 22) | def setUp(self):
    method test_request_success (line 30) | def test_request_success(self, mock_obj):
  class LocalPackageScanResultTest (line 43) | class LocalPackageScanResultTest(AutoLoginTest):
    method setUp (line 44) | def setUp(self):
    method test_get_failed_1 (line 66) | def test_get_failed_1(self):
    method test_get_failed_2 (line 72) | def test_get_failed_2(self):
    method get_success_resp (line 82) | def get_success_resp(self):
    method test_get_success (line 95) | def test_get_success(self):
    method test_checking_status (line 98) | def test_checking_status(self):
    method test_check_all_failed_status (line 103) | def test_check_all_failed_status(self):
    method test_published_status (line 111) | def test_published_status(self):
    method test_publishing_status (line 119) | def test_publishing_status(self):

FILE: omp_server/tests/test_app_store/test_get_application_template.py
  class ApplicationTemplateTest (line 15) | class ApplicationTemplateTest(AutoLoginTest):
    method setUp (line 18) | def setUp(self):
    method test_get_application_template (line 22) | def test_get_application_template(self):

FILE: omp_server/tests/test_app_store/test_install_executor.py
  class TestInstallExecutor (line 11) | class TestInstallExecutor(TestCase, InstallHistoryResourceMixin):
    method test_action (line 14) | def test_action(self):
    method test_main (line 98) | def test_main(self, mock_send, mock_unzip, mock_install, mock_init, mo...

FILE: omp_server/tests/test_app_store/test_upload_package.py
  class UploadPackageTest (line 17) | class UploadPackageTest(AutoLoginTest):
    method setUp (line 20) | def setUp(self):
    method create_fake_file (line 24) | def create_fake_file(self, file_end):
    method test_error_field (line 34) | def test_error_field(self):
    method test_correct_field (line 101) | def test_correct_field(self):
    method tearDown (line 119) | def tearDown(self):
  class RemovePackageTest (line 130) | class RemovePackageTest(AutoLoginTest, UploadPackageHistoryMixin):
    method setUp (line 133) | def setUp(self):
    method test_error_field (line 137) | def test_error_field(self):
    method test_correct_field (line 189) | def test_correct_field(self):

FILE: omp_server/tests/test_hosts/test_celery_tasks.py
  class HostCeleryTaskTest (line 28) | class HostCeleryTaskTest(BaseTest):
    method setUp (line 31) | def setUp(self):
    method test_deploy_agent_success (line 47) | def test_deploy_agent_success(self, *args, **kwargs):
    method test_deploy_agent_failed (line 57) | def test_deploy_agent_failed(self, *args, **kwargs):
    method test_deploy_agent_failed_with_wrong_id (line 67) | def test_deploy_agent_failed_with_wrong_id(self, *args, **kwargs):
    method test_real_deploy_agent_success (line 76) | def test_real_deploy_agent_success(self, *args, **kwargs):
    method test_real_deploy_agent_failed (line 86) | def test_real_deploy_agent_failed(self, *args, **kwargs):
    method test_restart_agent_success (line 94) | def test_restart_agent_success(self, agent_deploy):
    method test_restart_agent_failed (line 102) | def test_restart_agent_failed(self, agent_deploy):
    method test_restart_agent_failed_with_wrong_id (line 110) | def test_restart_agent_failed_with_wrong_id(self, agent_deploy):
    method test_real_restart_agent_success (line 118) | def test_real_restart_agent_success(self, agent_deploy):
    method test_real_restart_agent_failed (line 126) | def test_real_restart_agent_failed(self, agent_deploy):
    method test_deploy_monitor_agent_success (line 135) | def test_deploy_monitor_agent_success(self, *args, **kwargs):
    method test_deploy_monitor_agent_false (line 146) | def test_deploy_monitor_agent_false(self, *args, **kwargs):
    method test_deploy_monitor_agent_failed (line 157) | def test_deploy_monitor_agent_failed(self, *args, **kwargs):

FILE: omp_server/tests/test_hosts/test_hosts.py
  class CreateHostTest (line 28) | class CreateHostTest(AutoLoginTest, HostsResourceMixin):
    method setUp (line 31) | def setUp(self):
    method test_error_field_instance_name (line 45) | def test_error_field_instance_name(self):
    method test_error_field_ip (line 111) | def test_error_field_ip(self):
    method test_error_field_port (line 146) | def test_error_field_port(self):
    method test_error_field_username (line 169) | def test_error_field_username(self):
    method test_error_field_password (line 202) | def test_error_field_password(self):
    method test_error_field_data_folder (line 257) | def test_error_field_data_folder(self):
    method test_error_field_operate_system (line 290) | def test_error_field_operate_system(self):
    method test_wrong_ssh (line 314) | def test_wrong_ssh(self, ssh_mock):
    method test_correct_field (line 342) | def test_correct_field(self, celery_task_mock, cmd_mock, is_sudo, ssh_...
  class ListHostTest (line 392) | class ListHostTest(AutoLoginTest, HostsResourceMixin, GrafanaMainPageRes...
    method setUp (line 395) | def setUp(self):
    method tearDown (line 402) | def tearDown(self):
    method mock_prometheus_info (line 407) | def mock_prometheus_info(host_obj_ls):
    method test_hosts_list_filter (line 430) | def test_hosts_list_filter(self):
    method test_hosts_list_order (line 452) | def test_hosts_list_order(self):
  class HostDetailTest (line 510) | class HostDetailTest(AutoLoginTest, HostsResourceMixin):
    method setUp (line 513) | def setUp(self):
    method tearDown (line 517) | def tearDown(self):
    method test_host_detail (line 521) | def test_host_detail(self):
  class UpdateHostTest (line 531) | class UpdateHostTest(AutoLoginTest, HostsResourceMixin):
    method setUp (line 534) | def setUp(self):
    method tearDown (line 538) | def tearDown(self):
    method test_update_host (line 545) | def test_update_host(self, cmd_mock, is_sudo, ssh_mock):
    method test_partial_update_host (line 624) | def test_partial_update_host(self, cmd, is_sudo, ssh_mock):
  class HostFieldCheckTest (line 681) | class HostFieldCheckTest(AutoLoginTest, HostsResourceMixin):
    method setUp (line 684) | def setUp(self):
    method tearDown (line 689) | def tearDown(self):
    method test_create_host_check (line 692) | def test_create_host_check(self):
    method test_error_host_check (line 735) | def test_error_host_check(self):
  class ListIPTest (line 787) | class ListIPTest(AutoLoginTest, HostsResourceMixin):
    method setUp (line 790) | def setUp(self):
    method tearDown (line 795) | def tearDown(self):
    method test_ip_list (line 799) | def test_ip_list(self):
  class HostMaintainTest (line 811) | class HostMaintainTest(AutoLoginTest, HostsResourceMixin):
    method setUp (line 814) | def setUp(self):
    method tearDown (line 819) | def tearDown(self):
    method test_error_field (line 823) | def test_error_field(self):
    method test_correct_field (line 855) | def test_correct_field(self, mock_down, mock_up):
    method test_alert_manager_error (line 912) | def test_alert_manager_error(self, mock_down, mock_up):
  class HostAgentRestartTest (line 972) | class HostAgentRestartTest(AutoLoginTest, HostsResourceMixin):
    method setUp (line 975) | def setUp(self):
    method tearDown (line 980) | def tearDown(self):
    method test_success (line 985) | def test_success(self, host_agent_restart_mock):
    method test_failed (line 1002) | def test_failed(self, host_agent_restart_mock):
  class HostBatchValidateTest (line 1012) | class HostBatchValidateTest(AutoLoginTest, HostsResourceMixin, HostBatch...
    method setUp (line 1015) | def setUp(self):
    method create_repeat_data (line 1021) | def create_repeat_data(host_list, field_name):
    method test_get_host_batch_template (line 1043) | def test_get_host_batch_template(self):
    method test_error_format (line 1057) | def test_error_format(self, celery_task_mock, cmd_mock, is_sudo, ssh_m...
    method test_batch_validate_error_field (line 1074) | def test_batch_validate_error_field(self, celery_task_mock, cmd_mock, ...
    method test_batch_validate_correct_field (line 1132) | def test_batch_validate_correct_field(self, celery_task_mock, cmd_mock...
  class HostBatchImportTest (line 1152) | class HostBatchImportTest(AutoLoginTest, HostsResourceMixin, HostBatchRe...
    method setUp (line 1155) | def setUp(self):
    method test_error_format (line 1163) | def test_error_format(self, celery_task_mock, cmd_mock, is_sudo, ssh_m...
    method test_batch_import (line 1180) | def test_batch_import(self, celery_task_mock, cmd_mock, is_sudo, ssh_m...

FILE: omp_server/tests/test_inspection/inspection_mixin.py
  class InspectionHistoryMixin (line 11) | class InspectionHistoryMixin:
    method get_inspection_history (line 13) | def get_inspection_history(env):
    method create_inspection_crontab (line 29) | def create_inspection_crontab(env):
    method update_inspection_crontab (line 39) | def update_inspection_crontab():
    method get_inspection_crontab (line 49) | def get_inspection_crontab():
  class InspectionReportMixin (line 54) | class InspectionReportMixin:
    method create_inspection_report (line 56) | def create_inspection_report(env):
    method update_inspection_report (line 67) | def update_inspection_report(inst_id):

FILE: omp_server/tests/test_inspection/test_crontab.py
  class TestInspectionCrontabList (line 11) | class TestInspectionCrontabList(AutoLoginTest, InspectionHistoryMixin):
    method setUp (line 12) | def setUp(self):
    method tearDown (line 16) | def tearDown(self):
    method test_crontab_read (line 19) | def test_crontab_read(self):
    method test_crontab_create (line 25) | def test_crontab_create(self):
    method test_crontab_update (line 36) | def test_crontab_update(self):

FILE: omp_server/tests/test_inspection/test_history.py
  class TestInspectionHistoryList (line 12) | class TestInspectionHistoryList(AutoLoginTest, InspectionHistoryMixin):
    method setUp (line 13) | def setUp(self):
    method tearDown (line 17) | def tearDown(self):
    method test_history_list (line 20) | def test_history_list(self):
    method test_history_post (line 37) | def test_history_post(self, tasks):

FILE: omp_server/tests/test_inspection/test_inspection_email.py
  class MockResponse (line 8) | class MockResponse:
    method __init__ (line 14) | def __init__(self, data):
    method json (line 18) | def json(self):
  class InspectionEmail (line 22) | class InspectionEmail(AutoLoginTest, InspectionHistoryMixin):
    method setUp (line 24) | def setUp(self):
    method tearDown (line 30) | def tearDown(self):
    method test_get_inspection_email_config (line 33) | def test_get_inspection_email_config(self):
    method test_update_inspection_email_config (line 39) | def test_update_inspection_email_config(self):

FILE: omp_server/tests/test_inspection/test_report.py
  class TestInspectionReportList (line 11) | class TestInspectionReportList(AutoLoginTest, InspectionReportMixin):
    method setUp (line 12) | def setUp(self):
    method tearDown (line 16) | def tearDown(self):
    method test_crontab_read (line 19) | def test_crontab_read(self):

FILE: omp_server/tests/test_promemonitor/test_alert.py
  class MockResponse (line 10) | class MockResponse:
    method __init__ (line 16) | def __init__(self, data):
    method json (line 19) | def json(self):
  class AlertTest (line 23) | class AlertTest(AutoLoginTest):
    method setUp (line 26) | def setUp(self):
    method test_get_alerts (line 51) | def test_get_alerts(self):
    method test_update_is_read (line 82) | def test_update_is_read(self, mock_post):
    method tearDown (line 94) | def tearDown(self):

FILE: omp_server/tests/test_promemonitor/test_alertmanager.py
  class MockResponse (line 11) | class MockResponse:
    method __init__ (line 17) | def __init__(self, data):
    method json (line 20) | def json(self):
  class TestAlertmanager (line 24) | class TestAlertmanager(TestCase):
    method setUp (line 29) | def setUp(self):
    method return_host_list (line 34) | def return_host_list():
    method return_set_alertmanager_maintain_response (line 56) | def return_set_alertmanager_maintain_response():
    method return_revoke_alertmanager_maintain_response (line 62) | def return_revoke_alertmanager_maintain_response():
    method test_set_maintain_by_host_list (line 67) | def test_set_maintain_by_host_list(self, mock_post):
    method test_set_maintain_by_env_name (line 76) | def test_set_maintain_by_env_name(self, mock_post):
    method test_revoke_alertmanager_maintain_by_host_list (line 84) | def test_revoke_alertmanager_maintain_by_host_list(self, mock_post):
    method test_revoke_alertmanager_maintain_by_env_name (line 98) | def test_revoke_alertmanager_maintain_by_env_name(self, mock_post):
    method test_error_alertmanager_func1 (line 105) | def test_error_alertmanager_func1(self, mock_post):
    method test_error_alertmanager_func2 (line 123) | def test_error_alertmanager_func2(self):
    method tearDown (line 140) | def tearDown(self):

FILE: omp_server/tests/test_promemonitor/test_celery_tasks.py
  class MonitorAgentRestartCeleryTaskTest (line 18) | class MonitorAgentRestartCeleryTaskTest(BaseTest):
    method setUp (line 21) | def setUp(self):
    method test_restart_monitor_agent_success (line 37) | def test_restart_monitor_agent_success(self, *args, **kwargs):
    method test_restart_agent_failed (line 47) | def test_restart_agent_failed(self, *args, **kwargs):
    method test_restart_agent_failed_with_wrong_id (line 57) | def test_restart_agent_failed_with_wrong_id(self, *args, **kwargs):
    method test_real_restart_monitor_agent_success (line 66) | def test_real_restart_monitor_agent_success(self, *args, **kwargs):
    method test_real_restart_monitor_agent_failed (line 76) | def test_real_restart_monitor_agent_failed(self, *args, **kwargs):

FILE: omp_server/tests/test_promemonitor/test_email_config.py
  class MockResponse (line 15) | class MockResponse:
    method __init__ (line 21) | def __init__(self, data):
    method json (line 25) | def json(self):
  class EmailConfig (line 29) | class EmailConfig(AutoLoginTest):
    method delete_conf_dir (line 32) | def delete_conf_dir():
    method setUp (line 42) | def setUp(self):
    method tearDown (line 84) | def tearDown(self):
    method test_get_email_smtp_config (line 90) | def test_get_email_smtp_config(self):
    method test_update_smtp_config (line 97) | def test_update_smtp_config(self, mock_post=None):
    method test_get_send_alert_config (line 111) | def test_get_send_alert_config(self):
    method test_update_send_alert_config (line 118) | def test_update_send_alert_config(self, mock_post=None):

FILE: omp_server/tests/test_promemonitor/test_global_maintain.py
  class MockResponse (line 12) | class MockResponse:
    method __init__ (line 18) | def __init__(self, data):
    method json (line 21) | def json(self):
  class GlobalMaintainTest (line 25) | class GlobalMaintainTest(AutoLoginTest):
    method setUp (line 28) | def setUp(self):
    method return_set_alertmanager_maintain_response (line 40) | def return_set_alertmanager_maintain_response():
    method return_revoke_alertmanager_maintain_response (line 46) | def return_revoke_alertmanager_maintain_response():
    method test_set_global_maintain (line 51) | def test_set_global_maintain(self, mock_post):
    method revoke_global_maintain (line 65) | def revoke_global_maintain(self, maintain_data, mock_post=''):
    method tearDown (line 71) | def tearDown(self):

FILE: omp_server/tests/test_promemonitor/test_grafana_url.py
  class GrafanaUrlTest (line 68) | class GrafanaUrlTest(AutoLoginTest, GrafanaMainPageResourceMixin):
    method setUp (line 69) | def setUp(self):
    method test_exception_list (line 75) | def test_exception_list(self, curl_prometheus):
    method test_exception_list_filter (line 82) | def test_exception_list_filter(self, curl_prometheus):

FILE: omp_server/tests/test_promemonitor/test_grafana_views.py
  class MockResponse (line 21) | class MockResponse(object):
    method __init__ (line 26) | def __init__(self, headers=None):
  class TestGrafanaViews (line 32) | class TestGrafanaViews(BaseTest):
    method setUp (line 34) | def setUp(self):
    method test_success (line 41) | def test_success(self, request):
    method test_failed_connected (line 47) | def test_failed_connected(self, request):

FILE: omp_server/tests/test_promemonitor/test_instance_name_list.py
  class GetInstanceNameListTest (line 6) | class GetInstanceNameListTest(AutoLoginTest):
    method setUp (line 9) | def setUp(self):
    method test_get_instance_name_list (line 13) | def test_get_instance_name_list(self):

FILE: omp_server/tests/test_promemonitor/test_instrument_panel.py
  class MockResponse (line 11) | class MockResponse:
    method __init__ (line 17) | def __init__(self, data):
    method json (line 20) | def json(self):
  class InstrumentPanelTest (line 24) | class InstrumentPanelTest(AutoLoginTest):
    method setUp (line 26) | def setUp(self):
    method return_prometheus_alerts_response (line 33) | def return_prometheus_alerts_response():
    method test_instrument_panel (line 140) | def test_instrument_panel(self, mock_get):
    method tearDown (line 147) | def tearDown(self):

FILE: omp_server/tests/test_promemonitor/test_monitor_agent_restart.py
  class MonitorAgentRestartTest (line 19) | class MonitorAgentRestartTest(AutoLoginTest, HostsResourceMixin):
    method setUp (line 22) | def setUp(self):
    method test_success (line 27) | def test_success(self, monitor_agent_restart_obj):
    method test_failed (line 47) | def test_failed(self, monitor_agent_restart_obj):

FILE: omp_server/tests/test_promemonitor/test_promemonitor_url.py
  class PromemonitorTest (line 7) | class PromemonitorTest(AutoLoginTest):
    method setUp (line 9) | def setUp(self):
    method test_list_promeurl (line 23) | def test_list_promeurl(self):
    method test_create_promeurl (line 32) | def test_create_promeurl(self):
    method test_partial_update_promeurl (line 137) | def test_partial_update_promeurl(self):

FILE: omp_server/tests/test_promemonitor/test_prometheus.py
  class MockResponse (line 12) | class MockResponse:
    method __init__ (line 18) | def __init__(self, data):
    method json (line 21) | def json(self):
  class TestPrometheus (line 25) | class TestPrometheus(TestCase):
    method setUp (line 27) | def setUp(self):
    method return_host_list (line 44) | def return_host_list():
    method return_host_info_data (line 54) | def return_host_info_data():
    method test_get_prometheus_info (line 77) | def test_get_prometheus_info(self, mock_post):
    method test_get_host_metric_status (line 85) | def test_get_host_metric_status(self):
    method test_error_get_host_arg_usage (line 97) | def test_error_get_host_arg_usage(self, mock_get):
    method tearDown (line 153) | def tearDown(self):

FILE: omp_server/tests/test_promemonitor/test_prometheus_utils.py
  class MockResponse (line 25) | class MockResponse:
    method __init__ (line 31) | def __init__(self, data):
    method json (line 34) | def json(self):
  class PrometheusUtilsTest (line 38) | class PrometheusUtilsTest(BaseTest):
    method delete_conf_dir (line 42) | def delete_conf_dir():
    method setUp (line 51) | def setUp(self):
    method test_init_success (line 70) | def test_init_success(self):
    method test_add_node_failed_with_null_data (line 78) | def test_add_node_failed_with_null_data(self):
    method test_add_node_success (line 87) | def test_add_node_success(self):
    method test_add_node_success_2 (line 95) | def test_add_node_success_2(self):
    method test_add_node_success_3 (line 111) | def test_add_node_success_3(self):
    method test_delete_node_failed_with_null_data (line 128) | def test_delete_node_failed_with_null_data(self):
    method test_delete_node_success (line 135) | def test_delete_node_success(self):
    method test_delete_node_failed_with_file_not_exist (line 144) | def test_delete_node_failed_with_file_not_exist(self):
    method test_delete_node_success_with_empty_file (line 152) | def test_delete_node_success_with_empty_file(self):
    method test_add_rules_failed (line 162) | def test_add_rules_failed(self):
    method test_add_rules_for_node_success (line 169) | def test_add_rules_for_node_success(self):
    method test_add_rules_for_service_success (line 176) | def test_add_rules_for_service_success(self):
    method test_add_rules_for_exporter_success (line 183) | def test_add_rules_for_exporter_success(self):
    method test_delete_rules_failed (line 190) | def test_delete_rules_failed(self):
    method test_delete_rules_for_node_success (line 197) | def test_delete_rules_for_node_success(self):
    method test_delete_rules_for_service_success (line 204) | def test_delete_rules_for_service_success(self):
    method test_delete_rules_for_exporter_success (line 211) | def test_delete_rules_for_exporter_success(self):
    method test_replace_placeholder_failed (line 219) | def test_replace_placeholder_failed(self):
    method test_add_service (line 231) | def test_add_service(self, mock_post):
    method test_delete_service (line 258) | def test_delete_service(self, mock_post):
    method tearDown (line 288) | def tearDown(self) -> None:

FILE: omp_server/tests/test_promemonitor/test_receive_alert.py
  class MockResponse (line 9) | class MockResponse:
    method __init__ (line 15) | def __init__(self, data):
    method json (line 18) | def json(self):
  class ReceiveAlertTest (line 22) | class ReceiveAlertTest(AutoLoginTest):
    method setUp (line 25) | def setUp(self):
    method test_receive_alerts (line 119) | def test_receive_alerts(self):
    method test_alert_util_exception (line 130) | def test_alert_util_exception(self):
    method tearDown (line 142) | def tearDown(self):

FILE: omp_server/tests/test_promemonitor/test_threshold_rw.py
  class MockResponse (line 14) | class MockResponse:
    method __init__ (line 20) | def __init__(self, data):
    method json (line 24) | def json(self):
  class ThresholdRW (line 28) | class ThresholdRW(AutoLoginTest):
    method delete_conf_dir (line 31) | def delete_conf_dir():
    method setUp (line 41) | def setUp(self):
    method tearDown (line 82) | def tearDown(self):
    method test_get_host_threshold_config (line 89) | def test_get_host_threshold_config(self):
    method test_update_host_threshold_config (line 96) | def test_update_host_threshold_config(self, mock_post=None):
    method test_get_service_threshold_config (line 118) | def test_get_service_threshold_config(self):
    method test_update_service_threshold_config (line 125) | def test_update_service_threshold_config(self, mock_post=None):
    method test_get_custom_threshold_config (line 147) | def test_get_custom_threshold_config(self):
    method test_update_custom_threshold_config (line 154) | def test_update_custom_threshold_config(self, mock_post=None):

FILE: omp_server/tests/test_services/test_service_actions.py
  class ListActionTest (line 37) | class ListActionTest(AutoLoginTest, ServicesResourceMixin):
    method setUp (line 40) | def setUp(self):
    method test_service_action_true (line 75) | def test_service_action_true(self, status):
    method test_service_action_false (line 89) | def test_service_action_false(self, status):
    method test_service_action_delete (line 110) | def test_service_action_delete(self, salt_client, delete_service, stat...
    method test_service_action_post (line 143) | def test_service_action_post(self, tasks):
    method test_service_delete_post (line 161) | def test_service_delete_post(self):

FILE: omp_server/tests/test_services/test_services.py
  class ListServiceTest (line 11) | class ListServiceTest(AutoLoginTest, ServicesResourceMixin):
    method setUp (line 14) | def setUp(self):
    method tearDown (line 19) | def tearDown(self):
    method test_services_list_filter (line 23) | def test_services_list_filter(self):
    method test_services_list_order (line 97) | def test_services_list_order(self):
  class ServiceDetailTest (line 125) | class ServiceDetailTest(AutoLoginTest, ServicesResourceMixin):
    method setUp (line 128) | def setUp(self):
    method tearDown (line 132) | def tearDown(self):
    method test_service_detail (line 136) | def test_service_detail(self):

FILE: omp_server/tests/test_users/test_login.py
  class LoginTest (line 8) | class LoginTest(BaseTest):
    method setUp (line 11) | def setUp(self):
    method get_interval_time (line 17) | def get_interval_time(gmt_time):
    method test_login (line 26) | def test_login(self):
    method test_access_api (line 90) | def test_access_api(self):
    method test_jwt_expiration (line 116) | def test_jwt_expiration(self):

FILE: omp_server/tests/test_users/test_users.py
  class UsersTest (line 7) | class UsersTest(AutoLoginTest):
    method get_user (line 11) | def get_user():
    method destroy_user (line 21) | def destroy_user():
    method setUp (line 26) | def setUp(self):
    method test_create_user (line 31) | def test_create_user(self):
    method test_list_user (line 84) | def test_list_user(self):
    method test_retrieve_user (line 93) | def test_retrieve_user(self):
    method test_update_user (line 118) | def test_update_user(self):
    method test_partial_update_user (line 163) | def test_partial_update_user(self):
    method test_delete_user (line 193) | def test_delete_user(self):
  class UserUpdatePasswordTest (line 209) | class UserUpdatePasswordTest(AutoLoginTest):
    method setUp (line 212) | def setUp(self):
    method test_update_password (line 216) | def test_update_password(self):

FILE: omp_server/tests/test_utils/test_agent_util.py
  class AgentUtilTest (line 23) | class AgentUtilTest(BaseTest):
    method setUp (line 26) | def setUp(self):
    method test_deploy_agent_success (line 42) | def test_deploy_agent_success(self, check, cmd, file_push):
    method test_deploy_agent_false_ssh (line 52) | def test_deploy_agent_false_ssh(self, check, cmd, file_push):
    method test_deploy_agent_false_cmd (line 62) | def test_deploy_agent_false_cmd(self, check, cmd, file_push):
    method test_deploy_agent_false_agent_file (line 72) | def test_deploy_agent_false_agent_file(self, check, cmd, file_push):
    method test_deploy_agent_false_file_config (line 82) | def test_deploy_agent_false_file_config(self, file_push, cmd, check):
    method test_deploy_agent_false_file_script (line 94) | def test_deploy_agent_false_file_script(self, file_push, cmd, check):
    method test_deploy_agent_false_start (line 106) | def test_deploy_agent_false_start(self, file_push, cmd, check):
    method test_deploy_agent_success_start (line 118) | def test_deploy_agent_success_start(self, file_push, cmd, check):
    method test_deploy_agent_false_generate_conf (line 134) | def test_deploy_agent_false_generate_conf(self, check, cmd, file_push,...
    method test_agent_start_success (line 143) | def test_agent_start_success(self, cmd, check):
    method test_agent_start_failed (line 153) | def test_agent_start_failed(self, cmd, check):
    method test_agent_stop_success (line 163) | def test_agent_stop_success(self, cmd, check):
    method test_agent_stop_failed (line 173) | def test_agent_stop_failed(self, cmd, check):
    method test_agent_status_success (line 183) | def test_agent_status_success(self, cmd, check):
    method test_agent_status_failed (line 193) | def test_agent_status_failed(self, cmd, check):
    method test_agent_restart_success (line 203) | def test_agent_restart_success(self, cmd, check):
    method test_agent_restart_failed (line 213) | def test_agent_restart_failed(self, cmd, check):
    method test_agent_method_failed (line 223) | def test_agent_method_failed(self, cmd, check):

FILE: omp_server/tests/test_utils/test_crontab_utils.py
  class CrontabUtilTest (line 21) | class CrontabUtilTest(BaseTest):
    method setUp (line 22) | def setUp(self):
    method test_create_crontab_job (line 32) | def test_create_crontab_job(self):
    method test_create_internal_job (line 46) | def test_create_internal_job(self):
    method test_create_internal_failed (line 56) | def test_create_internal_failed(self):

FILE: omp_server/tests/test_utils/test_crypto.py
  class CryptoUtilTest (line 13) | class CryptoUtilTest(BaseTest):
    method setUp (line 16) | def setUp(self):
    method test_encode_success (line 22) | def test_encode_success(self):
    method test_decode_success (line 29) | def test_decode_success(self):

FILE: omp_server/tests/test_utils/test_monitor_agent.py
  class MonitorAgentTest (line 25) | class MonitorAgentTest(BaseTest):
    method setUp (line 28) | def setUp(self):
    method _install (line 53) | def _install(self):
    method test_package_do_not_exist (line 61) | def test_package_do_not_exist(self, *args, **kwargs):
    method test_install_failed_send_package (line 76) | def test_install_failed_send_package(self, *args, **kwargs):
    method test_install_failed_cmd (line 89) | def test_install_failed_cmd(self, *args, **kwargs):
    method test_install_success (line 103) | def test_install_success(self, *args, **kwargs):
    method test_uninstall_failed (line 115) | def test_uninstall_failed(self, *args, **kwargs):
    method test_uninstall_success (line 128) | def test_uninstall_success(self, *args, **kwargs):

FILE: omp_server/tests/test_utils/test_public_utils.py
  class GetFileMd5Test (line 23) | class GetFileMd5Test(BaseTest):
    method setUp (line 26) | def setUp(self):
    method test_get_md5_failed_file_not_exist (line 30) | def test_get_md5_failed_file_not_exist(self):
    method test_get_md5_success (line 39) | def test_get_md5_success(self):
  class CheckIpPortTest (line 48) | class CheckIpPortTest(BaseTest):
    method setUp (line 51) | def setUp(self):
    method test_success (line 55) | def test_success(self, *args, **kwargs):
    method test_failed (line 60) | def test_failed(self, *args, **kwargs):
    method test_failed_with_ip_wrong (line 64) | def test_failed_with_ip_wrong(self):
    method test_failed_with_port_wrong (line 69) | def test_failed_with_port_wrong(self):
    method test_failed_with_port_str (line 74) | def test_failed_with_port_str(self):

FILE: omp_server/tests/test_utils/test_salt_client.py
  class SaltClientUtilTest (line 20) | class SaltClientUtilTest(BaseTest):
    method setUp (line 24) | def setUp(self, local_client):
    method test_salt_module_update_failed (line 30) | def test_salt_module_update_failed(self, local_client):
    method test_salt_module_update_success (line 42) | def test_salt_module_update_success(self, local_client):
    method test_fun_for_multi_failed (line 50) | def test_fun_for_multi_failed(self, local_client):
    method test_fun_for_multi_success (line 59) | def test_fun_for_multi_success(self, local_client):
    method test_fun_failed (line 67) | def test_fun_failed(self, local_client):
    method test_fun_success (line 78) | def test_fun_success(self, local_client):
    method test_fun_failed_1 (line 86) | def test_fun_failed_1(self, local_client):
    method test_fun_failed_2 (line 94) | def test_fun_failed_2(self, local_client):
    method test_fun_failed_3 (line 102) | def test_fun_failed_3(self, local_client):
    method test_fun_failed_4 (line 110) | def test_fun_failed_4(self, local_client):
    method test_fun_failed_5 (line 118) | def test_fun_failed_5(self, local_client):
    method test_cmd_failed (line 126) | def test_cmd_failed(self, local_client):
    method test_cmd_success (line 137) | def test_cmd_success(self, local_client):
    method test_cmd_failed_1 (line 145) | def test_cmd_failed_1(self, local_client):
    method test_cmd_failed_2 (line 153) | def test_cmd_failed_2(self, local_client):
    method test_cmd_failed_3 (line 161) | def test_cmd_failed_3(self, local_client):
    method test_cmd_failed_4 (line 169) | def test_cmd_failed_4(self, local_client):
    method test_cmd_failed_5 (line 177) | def test_cmd_failed_5(self, local_client):
    method test_cp_file_failed (line 185) | def test_cp_file_failed(self, local_client):
    method test_cp_file_success (line 196) | def test_cp_file_success(self, local_client):
    method test_cp_file_failed_1 (line 204) | def test_cp_file_failed_1(self, local_client):
    method test_cp_file_failed_2 (line 212) | def test_cp_file_failed_2(self, local_client):
    method test_cp_file_failed_3 (line 220) | def test_cp_file_failed_3(self, local_client):
    method test_cp_file_failed_4 (line 228) | def test_cp_file_failed_4(self, local_client):

FILE: omp_server/tests/test_utils/test_ssh.py
  function get_ssh_obj (line 23) | def get_ssh_obj(username="root"):
  class ChannelMock (line 37) | class ChannelMock(object):
    method recv_exit_status (line 40) | def recv_exit_status(self):
  class StdoutMock (line 47) | class StdoutMock(object):
    method __init__ (line 50) | def __init__(self, content):
    method readline (line 54) | def readline(self):
    method readlines (line 61) | def readlines(self):
  class SshUtilTest (line 71) | class SshUtilTest(BaseTest):
    method setUp (line 74) | def setUp(self):
    method test_get_connection_failed (line 78) | def test_get_connection_failed(self):
    method test_get_connection_success (line 89) | def test_get_connection_success(self, *args, **kwargs):
    method test_is_sudo_success (line 102) | def test_is_sudo_success(self, exec_command, *args, **kwargs):
    method test_is_sudo_failed (line 116) | def test_is_sudo_failed(self, exec_command, *args, **kwargs):
    method test_is_sudo_failed_connected (line 125) | def test_is_sudo_failed_connected(self):
    method test_ssh_check_failed (line 137) | def test_ssh_check_failed(self, exec_command, *args, **kwargs):
    method test_ssh_check_success (line 151) | def test_ssh_check_success(self, exec_command, *args, **kwargs):
    method test_ssh_check_failed_connected (line 160) | def test_ssh_check_failed_connected(self):
    method test_ssh_cmd_failed (line 172) | def test_ssh_cmd_failed(self, exec_command, *args, **kwargs):
    method test_ssh_cmd_failed_connected (line 182) | def test_ssh_cmd_failed_connected(self):
    method test_ssh_cmd_success (line 194) | def test_ssh_cmd_success(self, exec_command, *args, **kwargs):
    method test_ssh_close_success (line 210) | def test_ssh_close_success(self, *args, **kwargs):
    method test_ssh_file_push_success (line 225) | def test_ssh_file_push_success(self, *args, **kwargs):
    method test_ssh_file_push_failed_exception (line 239) | def test_ssh_file_push_failed_exception(self, *args, **kwargs):
    method test_ssh_file_push_failed_connected (line 246) | def test_ssh_file_push_failed_connected(self):
    method test_make_remote_path_exist_root (line 258) | def test_make_remote_path_exist_root(self, *args, **kwargs):
    method test_make_remote_path_exist_not_root (line 270) | def test_make_remote_path_exist_not_root(self, *args, **kwargs):

FILE: omp_server/tool/apps.py
  class ToolConfig (line 4) | class ToolConfig(AppConfig):

FILE: omp_server/tool/find_tools.py
  class ValidForm (line 25) | class ValidForm:
    method __init__ (line 27) | def __init__(self, form_list):
    method base_valid (line 30) | def base_valid(self, form):
    method valid_file (line 43) | def valid_file(self, form):
    method valid_select (line 47) | def valid_select(self, form):
    method valid_input (line 59) | def valid_input(self, form):
    method __call__ (line 63) | def __call__(self, *args, **kwargs):
  class ValidToolTar (line 73) | class ValidToolTar:
    method __init__ (line 83) | def __init__(self, tmp_package, tar_file):
    method verify_args (line 88) | def verify_args(self, script_args):
    method verify_name (line 94) | def verify_name(self, name):
    method verify_desc (line 101) | def verify_desc(self, desc):
    method verify_labels (line 108) | def verify_labels(self, kind):
    method verify_spec (line 115) | def verify_spec(self, spec):
    method verify_output (line 137) | def verify_output(self, output):
    method verify_send_package (line 144) | def verify_send_package(self, send_package):
    method verify_script_name (line 152) | def verify_script_name(self, script_name):
    method verify_script_type (line 159) | def verify_script_type(self, script_type):
    method verify_yaml_info (line 168) | def verify_yaml_info(self, package_name):
    method read_read_me (line 185) | def read_read_me(self):
    method create_tool_info (line 191) | def create_tool_info(self, package_name, md5):
    method rm_tool_package (line 226) | def rm_tool_package(self):
    method __call__ (line 229) | def __call__(self, *args, **kwargs):
  function verify_tar_files (line 264) | def verify_tar_files(tmp_package, tar_files):
  function load_verify_tar (line 281) | def load_verify_tar(tar_name=None):
  function find_tools_package (line 304) | def find_tools_package(tar_name=None):

FILE: omp_server/tool/serializers.py
  class ToolInfoSerializer (line 14) | class ToolInfoSerializer(serializers.ModelSerializer):
    class Meta (line 15) | class Meta:
  class ToolDetailSerializer (line 21) | class ToolDetailSerializer(serializers.ModelSerializer):
    class Meta (line 30) | class Meta:
    method tools_boj_ls (line 39) | def tools_boj_ls(self, obj):
    method get_duration (line 46) | def get_duration(self, obj):
    method get_run_user (line 49) | def get_run_user(self, obj):
    method get_time_out (line 54) | def get_time_out(self, obj):
    method get_count (line 57) | def get_count(self, obj):
    method get_tool_detail (line 60) | def get_tool_detail(self, obj):
    method get_tool_args (line 79) | def get_tool_args(self, obj):
  class ToolFormDetailSerializer (line 92) | class ToolFormDetailSerializer(serializers.ModelSerializer):
    class Meta (line 95) | class Meta:
  class ToolListSerializer (line 101) | class ToolListSerializer(serializers.ModelSerializer):
    method get_used_number (line 105) | def get_used_number(self, obj):
    class Meta (line 108) | class Meta:
  class ToolInfoDetailSerializer (line 113) | class ToolInfoDetailSerializer(serializers.ModelSerializer):
    class Meta (line 116) | class Meta:
  class ToolTargetObjectHostSerializer (line 123) | class ToolTargetObjectHostSerializer(serializers.ModelSerializer):
    method get_host_agent_state (line 126) | def get_host_agent_state(self, obj):
    class Meta (line 131) | class Meta:
  class ToolTargetObjectServiceSerializer (line 137) | class ToolTargetObjectServiceSerializer(serializers.ModelSerializer):
    method get_host_agent_state (line 142) | def get_host_agent_state(self, obj):
    method get_modifiable_kwargs (line 148) | def get_modifiable_kwargs(self, obj):
    class Meta (line 166) | class Meta:
  class ValidFormAnswer (line 173) | class ValidFormAnswer:
    method __init__ (line 175) | def __init__(self, questions, answers):
    method valid_file (line 179) | def valid_file(self, question):
    method valid_select (line 192) | def valid_select(self, question):
    method valid_input (line 199) | def valid_input(self, question):
    method is_valid (line 202) | def is_valid(self):
  class ToolFormAnswerSerializer (line 215) | class ToolFormAnswerSerializer(serializers.Serializer):
    method verify_task_name (line 225) | def verify_task_name(self, value):
    method verify_host_info (line 230) | def verify_host_info(self, values):
    method verify_service_info (line 242) | def verify_service_info(self, values, tool):
    method verify_target_objs (line 265) | def verify_target_objs(self, values):
    method verify_runuser (line 273) | def verify_runuser(self, value):
    method verify_timeout (line 276) | def verify_timeout(self, value):
    method validate_default_form (line 281) | def validate_default_form(self, value):
    method validate_script_args (line 287) | def validate_script_args(self, value):
    method create (line 298) | def create(self, validated_data):
  class ToolExecuteHistoryListSerializer (line 369) | class ToolExecuteHistoryListSerializer(serializers.ModelSerializer):
    class Meta (line 372) | class Meta:

FILE: omp_server/tool/tasks.py
  class ThreadUtils (line 27) | class ThreadUtils:
    method __init__ (line 28) | def __init__(self):
    method send_message (line 35) | def send_message(tool_detail_obj, index=None, message=None):
    method receive_file (line 46) | def receive_file(self, tool_detail_obj, receive_files, ip):
    method __call__ (line 75) | def __call__(self, tool_detail_obj, *args, **kwargs):
  function exec_tools_main (line 129) | def exec_tools_main(tool_main_id):

FILE: omp_server/tool/tool_filters.py
  class ToolFilter (line 11) | class ToolFilter(FilterSet):
    class Meta (line 20) | class Meta:
  class ToolInfoKindFilter (line 25) | class ToolInfoKindFilter(BaseFilterBackend):
    method filter_queryset (line 27) | def filter_queryset(self, request, queryset, view):

FILE: omp_server/tool/views.py
  class ToolRetrieveAPIMixin (line 18) | class ToolRetrieveAPIMixin:
    method load_tool_obj (line 20) | def load_tool_obj(self):
  class GetToolDetailView (line 30) | class GetToolDetailView(GenericViewSet, RetrieveModelMixin):
  class ToolFormDetailAPIView (line 39) | class ToolFormDetailAPIView(GenericViewSet, RetrieveModelMixin):
  class ToolListView (line 45) | class ToolListView(GenericViewSet, ListModelMixin):
  class ToolDetailView (line 57) | class ToolDetailView(GenericViewSet, RetrieveModelMixin):
  class ToolTargetObjectAPIView (line 65) | class ToolTargetObjectAPIView(ListAPIView, ToolRetrieveAPIMixin):
    method get (line 69) | def get(self, request, *args, **kwargs):
    method get_queryset (line 73) | def get_queryset(self):
    method get_serializer_class (line 80) | def get_serializer_class(self):
  class ToolFormAnswerAPIView (line 86) | class ToolFormAnswerAPIView(CreateAPIView, ToolRetrieveAPIMixin):
    method post (line 90) | def post(self, request, *args, **kwargs):
  class ToolExecuteHistoryListApiView (line 95) | class ToolExecuteHistoryListApiView(ListAPIView):

FILE: omp_server/users/apps.py
  class UsersConfig (line 4) | class UsersConfig(AppConfig):

FILE: omp_server/users/users_filters.py
  class UserFilter (line 13) | class UserFilter(FilterSet):
    class Meta (line 18) | class Meta:
  class UserOperateFilter (line 23) | class UserOperateFilter(FilterSet):
    class Meta (line 29) | class Meta:
  class UserLoginOperateFilter (line 34) | class UserLoginOperateFilter(FilterSet):
    class Meta (line 40) | class Meta:

FILE: omp_server/users/users_serializers.py
  class UserSerializer (line 30) | class UserSerializer(ModelSerializer):
    class Meta (line 51) | class Meta:
    method validate_username (line 58) | def validate_username(self, username):
    method validate (line 70) | def validate(self, attrs):
  class OperateLogSerializer (line 84) | class OperateLogSerializer(ModelSerializer):
    class Meta (line 89) | class Meta:
    method get_create_time (line 97) | def get_create_time(self, obj):
  class UserLoginOperateSerializer (line 103) | class UserLoginOperateSerializer(ModelSerializer):
    class Meta (line 108) | class Meta:
    method get_login_time (line 113) | def get_login_time(self, obj):
  class JwtSerializer (line 119) | class JwtSerializer(JSONWebTokenSerializer):
    method validate (line 126) | def validate(self, attrs):
  class UserUpdatePasswordSerializer (line 132) | class UserUpdatePasswordSerializer(Serializer):
    method validate (line 150) | def validate(self, attrs):
    method create (line 165) | def create(self, validated_data):

FILE: omp_server/users/views.py
  class UsersView (line 48) | class UsersView(ListModelMixin, RetrieveModelMixin, CreateModelMixin,
  class OperateLogView (line 82) | class OperateLogView(ListModelMixin, RetrieveModelMixin, GenericViewSet):
  class UserLoginOperateView (line 100) | class UserLoginOperateView(ListModelMixin, RetrieveModelMixin, GenericVi...
  class JwtAPIView (line 119) | class JwtAPIView(JSONWebTokenAPIView):
    method validate_ip (line 127) | def validate_ip(str_ip):
    method _get_login_log (line 140) | def _get_login_log(request):
    method post (line 159) | def post(self, request, *args, **kwargs):
  class UserUpdatePasswordView (line 204) | class UserUpdatePasswordView(GenericViewSet, CreateModelMixin):
  class CaptchaView (line 216) | class CaptchaView(GenericViewSet, ListModelMixin):
    method list (line 224) | def list(self, request, *args, **kwargs):

FILE: omp_server/utils/common/exceptions.py
  class GeneralError (line 14) | class GeneralError(Exception):
    method __init__ (line 17) | def __init__(self, err="通用异常"):
  class OperateError (line 21) | class OperateError(GeneralError):
    method __init__ (line 24) | def __init__(self, err="操作发生错误"):
  function _validation_error_message (line 28) | def _validation_error_message(exc, response):

FILE: omp_server/utils/common/paginations.py
  class PageNumberPager (line 12) | class PageNumberPager(PageNumberPagination):
  class LimitOffsetPager (line 20) | class LimitOffsetPager(LimitOffsetPagination):
  class CursorPager (line 28) | class CursorPager(CursorPagination):

FILE: omp_server/utils/common/serializers.py
  class HostIdsSerializer (line 12) | class HostIdsSerializer(serializers.Serializer):
    method validate_host_ids (line 21) | def validate_host_ids(self, host_ids):
  class UploadFileSerializer (line 34) | class UploadFileSerializer(serializers.Serializer):
    method validate (line 53) | def validate(self, attrs):
    method create (line 71) | def create(self, validated_data):
  class DynamicFieldsModelSerializer (line 92) | class DynamicFieldsModelSerializer(serializers.ModelSerializer):
    method __init__ (line 98) | def __init__(self, *args, **kwargs):

FILE: omp_server/utils/common/validators.py
  class ReValidator (line 10) | class ReValidator:
    method __init__ (line 14) | def __init__(self, regex, message="格式不合法"):
    method __call__ (line 18) | def __call__(self, value, serializer_field):
  class NoEmojiValidator (line 26) | class NoEmojiValidator:
    method __init__ (line 30) | def __init__(self, message="不可含有表情"):
    method __call__ (line 33) | def __call__(self, value, serializer_field):
  class NoChineseValidator (line 41) | class NoChineseValidator:
    method __init__ (line 45) | def __init__(self, message="不可含有中文"):
    method __call__ (line 48) | def __call__(self, value, serializer_field):
  class UserPasswordValidator (line 56) | class UserPasswordValidator:
    method __init__ (line 60) | def __init__(self, message="格式不合法"):
    method __call__ (line 66) | def __call__(self, value, serializer_field):

FILE: omp_server/utils/common/views.py
  class BaseDownLoadTemplateView (line 17) | class BaseDownLoadTemplateView(GenericViewSet, ListModelMixin):
    method list (line 25) | def list(self, request, *args, **kwargs):
  class UploadFileAPIView (line 44) | class UploadFileAPIView(GenericViewSet, CreateModelMixin):

FILE: omp_server/utils/exception_handler.py
  class ExceptionResponse (line 27) | class ExceptionResponse:
    method __init__ (line 28) | def __init__(self, exc, context):
    method err_response (line 32) | def err_response(self):
  function common_exception_handler (line 63) | def common_exception_handler(exc, context):

FILE: omp_server/utils/middleware_handler.py
  function get_username_of_token (line 35) | def get_username_of_token(token):
  class OperationLogMiddleware (line 48) | class OperationLogMiddleware(MiddlewareMixin):
    method process_response (line 51) | def process_response(self, request, response):
  class RoleAuthenticationMiddleware (line 121) | class RoleAuthenticationMiddleware(MiddlewareMixin):
    method process_view (line 124) | def process_view(self, request, func, *args, **kwargs):

FILE: omp_server/utils/plugin/agent_util.py
  class Agent (line 26) | class Agent(object):
    method __init__ (line 29) | def __init__(self, host, port, username, password, install_dir):
    method generate_conf (line 59) | def generate_conf(self):
    method agent_deploy (line 81) | def agent_deploy(self):
    method agent_manage (line 176) | def agent_manage(self, action, install_app_dir):

FILE: omp_server/utils/plugin/captcha/captcha.py
  function check_code (line 10) | def check_code(width=120, height=38, char_length=4, font_file=font_path,...

FILE: omp_server/utils/plugin/crontab_utils.py
  class CrontabUtils (line 29) | class CrontabUtils(object):
    method __init__ (line 32) | def __init__(
    method create_crontab_job (line 55) | def create_crontab_job(
    method create_internal_job (line 84) | def create_internal_job(self, num, unit_type="minutes"):
    method check_task_exist (line 112) | def check_task_exist(self):
    method delete_job (line 119) | def delete_job(self):
  function change_task (line 131) | def change_task(task_id, data=dict()):
  function get_per_cron (line 160) | def get_per_cron(cron_args):
  function change_task (line 181) | def change_task(task_id, data=dict()):
  function maintain (line 204) | def maintain(f):

FILE: omp_server/utils/plugin/crypto.py
  class AESCryptor (line 10) | class AESCryptor:
    method __init__ (line 13) | def __init__(self):
    method pad (line 18) | def pad(text, block_size=32):
    method un_pad (line 23) | def un_pad(text):
    method encode (line 27) | def encode(self, plaintext):
    method decode (line 34) | def decode(self, ciphertext):
  function decrypt_rsa (line 42) | def decrypt_rsa(encrypt_str, private_key=settings.PRIVATE_KEY):

FILE: omp_server/utils/plugin/install_ntpdate.py
  class InstallNtpdate (line 14) | class InstallNtpdate(object):
    method __init__ (line 15) | def __init__(self, host_obj_list=None):
    method check_ntpdate_package (line 27) | def check_ntpdate_package(self):
    method get_config_dic (line 34) | def get_config_dic(self):
    method get_run_user (line 42) | def get_run_user(self):
    method execute (line 47) | def execute(host_obj_lst, thread_name_prefix, func):
    method _install_ntpdate (line 76) | def _install_ntpdate(self, host_obj):
    method install (line 125) | def install(self):

FILE: omp_server/utils/plugin/monitor_agent.py
  class MonitorAgentManager (line 27) | class MonitorAgentManager(object):
    method __init__ (line 30) | def __init__(self, host_objs=None):
    method check_monitor_agent_package (line 43) | def check_monitor_agent_package(self):
    method execute (line 55) | def execute(host_obj_lst, thread_name_prefix, func):
    method _install (line 84) | def _install(self, obj):
    method install (line 139) | def install(self):
    method parse_hosts_data (line 156) | def parse_hosts_data(self):
    method _uninstall (line 188) | def _uninstall(self, obj):
    method uninstall (line 210) | def uninstall(self):

FILE: omp_server/utils/plugin/public_utils.py
  function local_cmd (line 20) | def local_cmd(command):
  function get_file_md5 (line 38) | def get_file_md5(file_path):
  function check_is_ip_address (line 56) | def check_is_ip_address(value):
  function check_ip_port (line 69) | def check_ip_port(ip, port):
  class DurationTime (line 94) | class DurationTime:
    method __init__ (line 96) | def __init__(self, seconds):
    method analysis_day (line 100) | def analysis_day(self):
    method analysis_hour (line 105) | def analysis_hour(self):
    method analysis_minute (line 110) | def analysis_minute(self):
    method __call__ (line 115) | def __call__(self, *args, **kwargs):
  function timedelta_strftime (line 123) | def timedelta_strftime(timedelta):
  function file_md5 (line 141) | def file_md5(file_path):
  function format_location_size (line 150) | def format_location_size(size):

FILE: omp_server/utils/plugin/salt_client.py
  class SaltClient (line 28) | class SaltClient(object):
    method __init__ (line 31) | def __init__(self, config_path=salt_master_config):
    method salt_module_update (line 42) | def salt_module_update(self):
    method fun_for_multi (line 68) | def fun_for_multi(self, target, fun, arg=(), kwarg=None, timeout=None,...
    method fun (line 100) | def fun(self, target, fun, arg=(), kwarg=None, timeout=None):
    method cmd (line 140) | def cmd(self, target, command, timeout, real_timeout=None):
    method cp_file (line 178) | def cp_file(self, target, source_path, target_path, makedirs=True):
    method cp_push (line 214) | def cp_push(self, target, source_path, upload_path):

FILE: omp_server/utils/plugin/send_email.py
  class ResultThread (line 13) | class ResultThread(threading.Thread):
    method __init__ (line 18) | def __init__(self, target, args, name=''):
    method run (line 24) | def run(self):
    method get_result (line 27) | def get_result(self):
  class ModelSettingEmailBackend (line 31) | class ModelSettingEmailBackend:
    method load_settings (line 35) | def load_settings(self):
    method load_connection (line 45) | def load_connection(self):
  class SendEmailContent (line 52) | class SendEmailContent:
    method __init__ (line 60) | def __init__(self, _obj):
    method fetch_content (line 64) | def fetch_content(self):
    method fetch_html_content (line 72) | def fetch_html_content(self):
    method fetch_file_kwargs (line 76) | def fetch_file_kwargs(self):
    method fetch_file_content (line 84) | def fetch_file_content(self):
  class SendAlertEmailContent (line 92) | class SendAlertEmailContent(SendEmailContent):
  class SendBackupHistoryEmailContent (line 96) | class SendBackupHistoryEmailContent(SendEmailContent):
  class SendDeepInspectionEmailContent (line 101) | class SendDeepInspectionEmailContent(SendBackupHistoryEmailContent):
  class SendNormalInspectionEmailContent (line 106) | class SendNormalInspectionEmailContent(SendBackupHistoryEmailContent):
  class EmailSendTool (line 111) | class EmailSendTool(object):
    method __init__ (line 114) | def __init__(self, con_backend, content, users):
    method send (line 127) | def send(self):
  function many_send (line 156) | def many_send(connection, content, users):

FILE: omp_server/utils/plugin/ssh.py
  class SSH (line 17) | class SSH(object):
    method __init__ (line 20) | def __init__(self, hostname, port, username, password, timeout=SSH_CHE...
    method _get_connection (line 44) | def _get_connection(self):
    method check (line 67) | def check(self):
    method is_sudo (line 81) | def is_sudo(self):
    method cmd (line 96) | def cmd(self, command, timeout=SSH_CMD_TIMEOUT, get_pty=True):
    method make_remote_path_exist (line 116) | def make_remote_path_exist(self, remote_path):
    method file_push (line 136) | def file_push(self, file, remote_path="/tmp"):
    method close (line 159) | def close(self):

FILE: omp_server/utils/plugin/synch_grafana.py
  function make_request (line 11) | def make_request(url, headers, payload):
  function synch_grafana_info (line 36) | def synch_grafana_info():

FILE: omp_server/utils/prometheus/create_html_tar.py
  function cmd (line 12) | def cmd(command):
  function create_html_tar (line 22) | def create_html_tar(new_html_dir_name, report_data):

FILE: omp_server/utils/prometheus/prometheus.py
  class Prometheus (line 18) | class Prometheus(object):
    method __init__ (line 24) | def __init__(self):
    method query (line 30) | def query(self, expr):
    method clean_alert (line 49) | def clean_alert(alerts):
    method unified_job (line 75) | def unified_job(is_success, ret):
    method query_alerts (line 89) | def query_alerts(self):
  function back_fill (line 105) | def back_fill(history_id, report_id, host_data=None, serv_data=None,

FILE: omp_server/utils/prometheus/target_host.py
  function target_host_thread (line 18) | def target_host_thread(env, instance):
  class HostCrawl (line 74) | class HostCrawl(Prometheus):
    method __init__ (line 79) | def __init__(self, env, instance):
    method unified_job (line 87) | def unified_job(is_success, ret):
    method run_status (line 101) | def run_status(self):
    method run_time (line 107) | def run_time(self):
    method cpu_usage (line 125) | def cpu_usage(self):
    method iowait (line 134) | def iowait(self):
    method mem_usage (line 141) | def mem_usage(self):
    method disk_usage_root (line 151) | def disk_usage_root(self):
    method disk_usage_data (line 165) | def disk_usage_data(self):
    method rate_exchange_disk (line 182) | def rate_exchange_disk(self):
    method rate_cpu_io_wait (line 190) | def rate_cpu_io_wait(self):
    method inode_usage (line 196) | def inode_usage(self):
    method max_openfile (line 206) | def max_openfile(self):
    method sys_load (line 211) | def sys_load(self):
    method bandwidth (line 224) | def bandwidth(self):
    method throughput (line 239) | def throughput(self):
    method salt_json (line 254) | def salt_json(self):
    method run (line 275) | def run(self):

FILE: omp_server/utils/prometheus/target_service.py
  function get_port_and_status (line 62) | def get_port_and_status(i):
  function _joint (line 81) | def _joint(i, ret, basics, service_port, service_ports, service_status):
  function target_service_thread (line 111) | def target_service_thread(env, i):
  function target_service_run (line 149) | def target_service_run(env, services):

FILE: omp_server/utils/prometheus/target_service_arangodb.py
  class ServiceArangodbCrawl (line 10) | class ServiceArangodbCrawl(Prometheus):
    method __init__ (line 15) | def __init__(self, env, instance):
    method service_status (line 25) | def service_status(self):
    method run_time (line 31) | def run_time(self):
    method cpu_usage (line 48) | def cpu_usage(self):
    method mem_usage (line 55) | def mem_usage(self):
    method rocksdb_base_level (line 62) | def rocksdb_base_level(self):
    method client_connections (line 73) | def client_connections(self):
    method rocksdb_background_errors (line 84) | def rocksdb_background_errors(self):
    method arangodb_transactions_started (line 95) | def arangodb_transactions_started(self):
    method thread_numbers (line 106) | def thread_numbers(self):
    method rocksdb_cache_limit (line 117) | def rocksdb_cache_limit(self):
    method rocksdb_size_all_mem_tables (line 128) | def rocksdb_size_all_mem_tables(self):
    method rocksdb_cache_allocated (line 139) | def rocksdb_cache_allocated(self):
    method rocksdb_num_snapshots (line 150) | def rocksdb_num_snapshots(self):
    method arangodb_transactions_committed (line 161) | def arangodb_transactions_committed(self):
    method rocksdb_estimate_num_keys (line 172) | def rocksdb_estimate_num_keys(self):
    method rocksdb_actual_delayed_write_rate (line 183) | def rocksdb_actual_delayed_write_rate(self):
    method rocksdb_cache_hit_rate_recent (line 194) | def rocksdb_cache_hit_rate_recent(self):
    method arangodb_transactions_aborted (line 205) | def arangodb_transactions_aborted(self):
    method run (line 216) | def run(self):

FILE: omp_server/utils/prometheus/target_service_beanstalk.py
  class ServiceBeanstalkCrawl (line 10) | class ServiceBeanstalkCrawl(Prometheus):
    method __init__ (line 15) | def __init__(self, env, instance):
    method service_status (line 25) | def service_status(self):
    method run_time (line 31) | def run_time(self):
    method cpu_usage (line 48) | def cpu_usage(self):
    method mem_usage (line 55) | def mem_usage(self):
    method total_connections (line 62) | def total_connections(self):
    method total_jobs (line 74) | def total_jobs(self):
    method buried_jobs (line 86) | def buried_jobs(self):
    method delayed_jobs (line 98) | def delayed_jobs(self):
    method timeout_job_num (line 110) | def timeout_job_num(self):
    method stats_cmd_num (line 122) | def stats_cmd_num(self):
    method reverse_cmd_num (line 134) | def reverse_cmd_num(self):
    method release_cmd_num (line 146) | def release_cmd_num(self):
    method put_cmd_num (line 158) | def put_cmd_num(self):
    method peek_cmd_num (line 170) | def peek_cmd_num(self):
    method kick_cmd_num (line 182) | def kick_cmd_num(self):
    method ignore_cmd_num (line 194) | def ignore_cmd_num(self):
    method delete_cmd_num (line 206) | def delete_cmd_num(self):
    method bury_cmd_num (line 218) | def bury_cmd_num(self):
    method run (line 230) | def run(self):

FILE: omp_server/utils/prometheus/target_service_clickhouse.py
  class ServiceClickhouseCrawl (line 10) | class ServiceClickhouseCrawl(Prometheus):
    method __init__ (line 15) | def __init__(self, env, instance):
    method service_status (line 25) | def service_status(self):
    method run_time (line 31) | def run_time(self):
    method cpu_usage (line 48) | def cpu_usage(self):
    method mem_usage (line 55) | def mem_usage(self):
    method query_nums (line 62) | def query_nums(self):
    method merge_nums (line 73) | def merge_nums(self):
    method read_only_replica (line 84) | def read_only_replica(self):
    method replication (line 95) | def replication(self):
    method clickhouse_read (line 106) | def clickhouse_read(self):
    method clickhouse_write (line 117) | def clickhouse_write(self):
    method pool_tasks (line 128) | def pool_tasks(self):
    method connections (line 139) | def connections(self):
    method clickhouse_memory_tracking (line 150) | def clickhouse_memory_tracking(self):
    method run (line 161) | def run(self):

FILE: omp_server/utils/prometheus/target_service_elasticsearch.py
  class ServiceElasticsearchCrawl (line 10) | class ServiceElasticsearchCrawl(Prometheus):
    method __init__ (line 15) | def __init__(self, env, instance):
    method service_status (line 25) | def service_status(self):
    method run_time (line 31) | def run_time(self):
    method cpu_usage (line 48) | def cpu_usage(self):
    method mem_usage (line 55) | def mem_usage(self):
    method running_nodes (line 62) | def running_nodes(self):
    method active_data_nodes (line 73) | def active_data_nodes(self):
    method pending_tasks (line 84) | def pending_tasks(self):
    method active_shards (line 95) | def active_shards(self):
    method active_primary_shards (line 106) | def active_primary_shards(self):
    method initializing_shards (line 117) | def initializing_shards(self):
    method relocating_shards (line 128) | def relocating_shards(self):
    method unassigned_shards (line 139) | def unassigned_shards(self):
    method delayed_unassigned_shards (line 150) | def delayed_unassigned_shards(self):
    method documents_indexed (line 161) | def documents_indexed(self):
    method index_size (line 172) | def index_size(self):
    method documents_indexed_rate (line 183) | def documents_indexed_rate(self):
    method query_rate (line 194) | def query_rate(self):
    method queue_count (line 205) | def queue_count(self):
    method gc_seconds (line 216) | def gc_seconds(self):
    method thread_pool_rejections (line 227) | def thread_pool_rejections(self):
    method thread_pool_active_count (line 238) | def thread_pool_active_count(self):
    method avg_heap_in_15min (line 249) | def avg_heap_in_15min(self):
    method rx_rate_5m (line 260) | def rx_rate_5m(self):
    method tx_rate_5m (line 271) | def tx_rate_5m(self):
    method run (line 282) | def run(self):

FILE: omp_server/utils/prometheus/target_service_flink.py
  class ServiceFlinkCrawl (line 11) | class ServiceFlinkCrawl(Prometheus):
    method __init__ (line 16) | def __init__(self, env, instance):
    method service_status (line 26) | def service_status(self):
    method run_time (line 32) | def run_time(self):
    method cpu_usage (line 49) | def cpu_usage(self):
    method mem_usage (line 56) | def mem_usage(self):
    method salt_json (line 63) | def salt_json(self):
    method run (line 82) | def run(self):

FILE: omp_server/utils/prometheus/target_service_func.py
  function salt_json (line 10) | def salt_json(instance, func):

FILE: omp_server/utils/prometheus/target_service_gotty.py
  class ServiceGottyCrawl (line 11) | class ServiceGottyCrawl(Prometheus):
    method __init__ (line 16) | def __init__(self, env, instance):
    method service_status (line 26) | def service_status(self):
    method run_time (line 32) | def run_time(self):
    method cpu_usage (line 49) | def cpu_usage(self):
    method mem_usage (line 56) | def mem_usage(self):
    method salt_json (line 63) | def salt_json(self):
    method run (line 82) | def run(self):

FILE: omp_server/utils/prometheus/target_service_grafana.py
  class ServiceGrafanaCrawl (line 11) | class ServiceGrafanaCrawl(Prometheus):
    method __init__ (line 16) | def __init__(self, env, instance):
    method service_status (line 26) | def service_status(self):
    method run_time (line 32) | def run_time(self):
    method cpu_usage (line 49) | def cpu_usage(self):
    method mem_usage (line 56) | def mem_usage(self):
    method salt_json (line 63) | def salt_json(self):
    method run (line 82) | def run(self):

FILE: omp_server/utils/prometheus/target_service_hadoop.py
  class ServiceHadoopCrawl (line 11) | class ServiceHadoopCrawl(Prometheus):
    method __init__ (line 16) | def __init__(self, env, instance):
    method service_status (line 26) | def service_status(self):
    method run_time (line 32) | def run_time(self):
    method cpu_usage (line 49) | def cpu_usage(self):
    method mem_usage (line 56) | def mem_usage(self):
    method salt_json (line 63) | def salt_json(self):
    method run (line 82) | def run(self):

FILE: omp_server/utils/prometheus/target_service_httpd.py
  class ServiceHttpdCrawl (line 10) | class ServiceHttpdCrawl(Prometheus):
    method __init__ (line 15) | def __init__(self, env, instance):
    method run_time (line 25) | def run_time(self):
    method cpu_usage (line 42) | def cpu_usage(self):
    method mem_usage (line 49) | def mem_usage(self):
    method process_max_fds (line 56) | def process_max_fds(self):
    method process_cpu_seconds_total (line 67) | def process_cpu_seconds_total(self):
    method apache_accesses_total (line 78) | def apache_accesses_total(self):
    method apache_cpuload (line 89) | def apache_cpuload(self):
    method apache_workers (line 100) | def apache_workers(self):
    method http_request_size_bytes (line 111) | def http_request_size_bytes(self):
    method apache_scoreboard (line 122) | def apache_scoreboard(self):
    method run (line 133) | def run(self):

FILE: omp_server/utils/prometheus/target_service_ignite.py
  class ServiceIgniteCrawl (line 10) | class ServiceIgniteCrawl(Prometheus):
    method __init__ (line 15) | def __init__(self, env, instance):
    method service_status (line 25) | def service_status(self):
    method run_time (line 31) | def run_time(self):
    method cpu_usage (line 48) | def cpu_usage(self):
    method mem_usage (line 55) | def mem_usage(self):
    method ignite_started_thread_count (line 62) | def ignite_started_thread_count(self):
    method sent_messages_count (line 73) | def sent_messages_count(self):
    method ignite_received_messages_count (line 84) | def ignite_received_messages_count(self):
    method average_job_wait_time (line 95) | def average_job_wait_time(self):
    method current_job_wait_time (line 106) | def current_job_wait_time(self):
    method maximum_job_wait_time (line 117) | def maximum_job_wait_time(self):
    method average_job_execute_time (line 128) | def average_job_execute_time(self):
    method current_job_execute_time (line 139) | def current_job_execute_time(self):
    method maximum_job_execute_time (line 150) | def maximum_job_execute_time(self):
    method busy_time_percentage (line 161) | def busy_time_percentage(self):
    method ignite_busy_time_total (line 172) | def ignite_busy_time_total(self):
    method ignite_idle_time_total (line 183) | def ignite_idle_time_total(self):
    method current_daemon_thread_count (line 194) | def current_daemon_thread_count(self):
    method maximum_thread_count (line 205) | def maximum_thread_count(self):
    method current_thread_count (line 216) | def current_thread_count(self):
    method run (line 227) | def run(self):

FILE: omp_server/utils/prometheus/target_service_jvm_base.py
  class ServiceBase (line 9) | class ServiceBase(Prometheus):
    method __init__ (line 14) | def __init__(self, env, instance, job):
    method service_status (line 23) | def service_status(self):
    method run_time (line 30) | def run_time(self):
    method cpu_usage (line 48) | def cpu_usage(self):
    method mem_usage (line 57) | def mem_usage(self):
    method thread_num (line 69) | def thread_num(self):
    method load_average_1m (line 78) | def load_average_1m(self):
    method tomcat_sessions (line 87) | def tomcat_sessions(self):
    method files_max_files (line 96) | def files_max_files(self):
    method files_open_files (line 105) | def files_open_files(self):
    method cpu_count (line 114) | def cpu_count(self):
    method run (line 123) | def run(self):

FILE: omp_server/utils/prometheus/target_service_kafka.py
  class ServiceKafkaCrawl (line 10) | class ServiceKafkaCrawl(Prometheus):
    method __init__ (line 15) | def __init__(self, env, instance):
    method service_status (line 25) | def service_status(self):
    method run_time (line 31) | def run_time(self):
    method cpu_usage (line 48) | def cpu_usage(self):
    method mem_usage (line 55) | def mem_usage(self):
    method kafka_brokers (line 62) | def kafka_brokers(self):
    method process_open_fds (line 74) | def process_open_fds(self):
    method process_resident_memory_bytes (line 86) | def process_resident_memory_bytes(self):
    method run (line 98) | def run(self):

FILE: omp_server/utils/prometheus/target_service_mysql.py
  class ServiceMysqlCrawl (line 10) | class ServiceMysqlCrawl(Prometheus):
    method __init__ (line 15) | def __init__(self, env, instance):
    method service_status (line 25) | def service_status(self):
    method run_time (line 31) | def run_time(self):
    method cpu_usage (line 48) | def cpu_usage(self):
    method mem_usage (line 55) | def mem_usage(self):
    method slow_query (line 62) | def slow_query(self):
    method conn_num (line 68) | def conn_num(self):
    method max_connections (line 74) | def max_connections(self):
    method threads_running (line 80) | def threads_running(self):
    method qps (line 86) | def qps(self):
    method backup_status (line 93) | def backup_status(self):
    method run (line 99) | def run(self):

FILE: omp_server/utils/prometheus/target_service_nacos.py
  class ServiceNacosCrawl (line 9) | class ServiceNacosCrawl(Prometheus):
    method __init__ (line 14) | def __init__(self, env, instance):
    method service_status (line 23) | def service_status(self):
    method run_time (line 29) | def run_time(self):
    method cpu_usage (line 46) | def cpu_usage(self):
    method mem_usage (line 53) | def mem_usage(self):
    method service_count (line 60) | def service_count(self):
    method ip_count (line 71) | def ip_count(self):
    method config_count (line 82) | def config_count(self):
    method config_push_total (line 93) | def config_push_total(self):
    method threads (line 104) | def threads(self):
    method notify_rt (line 115) | def notify_rt(self):
    method long_polling (line 126) | def long_polling(self):
    method qps (line 137) | def qps(self):
    method leader_status (line 148) | def leader_status(self):
    method avg_push_cost (line 159) | def avg_push_cost(self):
    method max_push_cost (line 170) | def max_push_cost(self):
    method config_statistics (line 181) | def config_statistics(self):
    method health_check (line 192) | def health_check(self):
    method run (line 203) | def run(self):

FILE: omp_server/utils/prometheus/target_service_ntpd.py
  class ServiceNtpdCrawl (line 11) | class ServiceNtpdCrawl(Prometheus):
    method __init__ (line 16) | def __init__(self, env, instance):
    method service_status (line 26) | def service_status(self):
    method run_time (line 32) | def run_time(self):
    method cpu_usage (line 49) | def cpu_usage(self):
    method mem_usage (line 56) | def mem_usage(self):
    method salt_json (line 63) | def salt_json(self):
    method run (line 82) | def run(self):

FILE: omp_server/utils/prometheus/target_service_postgresql.py
  class ServicePostgresqlCrawl (line 10) | class ServicePostgresqlCrawl(Prometheus):
    method __init__ (line 15) | def __init__(self, env, instance):
    method service_status (line 25) | def service_status(self):
    method run_time (line 31) | def run_time(self):
    method cpu_usage (line 48) | def cpu_usage(self):
    method mem_usage (line 55) | def mem_usage(self):
    method current_fetch_data (line 62) | def current_fetch_data(self):
    method current_insert_data (line 73) | def current_insert_data(self):
    method current_update_data (line 84) | def current_update_data(self):
    method max_connections (line 95) | def max_connections(self):
    method open_file_descriptors (line 106) | def open_file_descriptors(self):
    method shared_buffers (line 117) | def shared_buffers(self):
    method effective_cache (line 128) | def effective_cache(self):
    method max_wal_size (line 139) | def max_wal_size(self):
    method random_page_cost (line 150) | def random_page_cost(self):
    method seq_page_cost (line 161) | def seq_page_cost(self):
    method max_worker_processes (line 172) | def max_worker_processes(self):
    method max_parallel_workers (line 183) | def max_parallel_workers(self):
    method run (line 194) | def run(self):

FILE: omp_server/utils/prometheus/target_service_prometheus.py
  class ServicePrometheusCrawl (line 10) | class ServicePrometheusCrawl(Prometheus):
    method __init__ (line 15) | def __init__(self, env, instance):
    method service_status (line 25) | def service_status(self):
    method run_time (line 31) | def run_time(self):
    method cpu_usage (line 48) | def cpu_usage(self):
    method mem_usage (line 55) | def mem_usage(self):
    method run (line 62) | def run(self):

FILE: omp_server/utils/prometheus/target_service_redis.py
  class ServiceRedisCrawl (line 9) | class ServiceRedisCrawl(Prometheus):
    method __init__ (line 14) | def __init__(self, env, instance):
    method service_status (line 23) | def service_status(self):
    method run_time (line 29) | def run_time(self):
    method cpu_usage (line 46) | def cpu_usage(self):
    method mem_usage (line 53) | def mem_usage(self):
    method conn_num (line 60) | def conn_num(self):
    method hit_rate (line 69) | def hit_rate(self):
    method max_memory (line 84) | def max_memory(self):
    method network_io (line 95) | def network_io(self):
    method run (line 112) | def run(self):

FILE: omp_server/utils/prometheus/target_service_rocketmq.py
  class ServiceRocketmqCrawl (line 11) | class ServiceRocketmqCrawl(Prometheus):
    method __init__ (line 16) | def __init__(self, env, instance):
    method service_status (line 26) | def service_status(self):
    method run_time (line 32) | def run_time(self):
    method cpu_usage (line 49) | def cpu_usage(self):
    method mem_usage (line 56) | def mem_usage(self):
    method broker_tps (line 63) | def broker_tps(self):
    method broker_qps (line 72) | def broker_qps(self):
    method message_accumulation (line 81) | def message_accumulation(self):
    method salt_json (line 90) | def salt_json(self):
    method run (line 108) | def run(self):

FILE: omp_server/utils/prometheus/target_service_tengine.py
  class ServiceTengineCrawl (line 10) | class ServiceTengineCrawl(Prometheus):
    method __init__ (line 15) | def __init__(self, env, instance):
    method service_status (line 25) | def service_status(self):
    method run_time (line 31) | def run_time(self):
    method cpu_usage (line 48) | def cpu_usage(self):
    method mem_usage (line 55) | def mem_usage(self):
    method server_connections (line 62) | def server_connections(self):
    method server_cache (line 73) | def server_cache(self):
    method server_requests (line 84) | def server_requests(self):
    method run (line 95) | def run(self):

FILE: omp_server/utils/prometheus/target_service_zookeeper.py
  class ServiceZookeeperCrawl (line 10) | class ServiceZookeeperCrawl(Prometheus):
    method __init__ (line 15) | def __init__(self, env, instance):
    method service_status (line 25) | def service_status(self):
    method run_time (line 31) | def run_time(self):
    method cpu_usage (line 48) | def cpu_usage(self):
    method mem_usage (line 55) | def mem_usage(self):
    method packets_received (line 62) | def packets_received(self):
    method packets_sent (line 71) | def packets_sent(self):
    method num_alive_connections (line 80) | def num_alive_connections(self):
    method outstanding_requests (line 89) | def outstanding_requests(self):
    method znode_count (line 98) | def znode_count(self):
    method watch_count (line 107) | def watch_count(self):
    method run (line 116) | def run(self):

FILE: omp_server/utils/prometheus/thread.py
  class MyThread (line 9) | class MyThread(threading.Thread):
    method __init__ (line 16) | def __init__(self, func, args):
    method run (line 22) | def run(self):
    method result (line 25) | def result(self):

FILE: omp_server/utils/prometheus/update_threshold.py
  function gen_summary (line 44) | def gen_summary(index_type):
  function replace_value (line 48) | def replace_value(line, env_name=None, condition=None, condition_value=N...
  function update_node_rule_yaml (line 65) | def update_node_rule_yaml(quotes_info):
  function update_service_rule_yaml (line 136) | def update_service_rule_yaml(quotes_info):
  function config_update (line 194) | def config_update(quotes_info):

FILE: omp_server/utils/prometheus/utils.py
  function get_host_data_folder (line 16) | def get_host_data_folder(instance):

FILE: omp_server/utils/response_handler.py
  class APIRenderer (line 16) | class APIRenderer(JSONRenderer):
    method render (line 19) | def render(self, data, accepted_media_type=None, renderer_context=None):

FILE: omp_web/src/components/CustomBreadcrumb/store/constants.js
  constant CHANGE_MAINTENANCE (line 1) | const CHANGE_MAINTENANCE = "CHANGE_MAINTENANCE";
  constant CHANGE_REFRESHTIME (line 3) | const CHANGE_REFRESHTIME = "CHANGE_REFRESHTIME";

FILE: omp_web/src/components/CustomBreadcrumb/store/reduer.js
  function reducer (line 7) | function reducer(state = defaultState,action){

FILE: omp_web/src/components/OmpContentWrapper/index.js
  function OmpContentWrapper (line 3) | function OmpContentWrapper({ children, wrapperStyle }) {

FILE: omp_web/src/components/OmpStateBlock/index.js
  function OmpStateBlock (line 25) | function OmpStateBlock(props) {
  function popContent (line 208) | function popContent(item) {

FILE: omp_web/src/layouts/store/constants.js
  constant SET_VIEWSIZE (line 1) | const SET_VIEWSIZE = "SET_VIEWSIZE";

FILE: omp_web/src/layouts/store/reduer.js
  function reducer (line 8) | function reducer(state = defaultState,action){

FILE: omp_web/src/pages/AlarmLog/index.js
  function fetchData (line 61) | function fetchData(

FILE: omp_web/src/pages/AppStore/config/ApplicationInstallation.js
  function fetchData (line 122) | function fetchData() {

FILE: omp_web/src/pages/AppStore/config/ComponentInstallation.js
  function fetchData (line 113) | function fetchData() {

FILE: omp_web/src/pages/AppStore/config/Installation/steps/Step3.js
  function queryIpList (line 53) | function queryIpList() {

FILE: omp_web/src/pages/AppStore/config/Installation/store/constants.js
  constant CHANGE_DATASOURCE (line 1) | const CHANGE_DATASOURCE = "CHANGE_DATASOURCE";
  constant CHANGE_IPLIST (line 3) | const CHANGE_IPLIST = "CHANGE_IPLIST";
  constant CHANGE_STEP1DATA (line 5) | const CHANGE_STEP1DATA = "CHANGE_STEP1DATA";
  constant CHANGE_STEP2DATA (line 7) | const CHANGE_STEP2DATA = "CHANGE_STEP2DATA";
  constant CHANGE_STEP2ERRORLISTDATA (line 8) | const CHANGE_STEP2ERRORLISTDATA = "CHANGE_STEP2ERRORLISTDATA";
  constant CHANGE_STEP3DATA (line 10) | const CHANGE_STEP3DATA = "CHANGE_STEP3DATA";
  constant CHANGE_STEP3SERVERDATA (line 11) | const CHANGE_STEP3SERVERDATA = "CHANGE_STEP3SERVERDATA";
  constant CHANGE_STEP3ERRORDATA (line 12) | const CHANGE_STEP3ERRORDATA = "CHANGE_STEP3ERRORDATA";

FILE: omp_web/src/pages/AppStore/config/Installation
Condensed preview — 659 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (7,002K chars).
[
  {
    "path": ".gitignore",
    "chars": 2691,
    "preview": "/omp_web/node_modules\n### Python template\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C"
  },
  {
    "path": ".pre-commit-config.yaml",
    "chars": 676,
    "preview": "default_stages: [commit]\nrepos:\n  - repo: https://github.com/yingzi113/pre-commit-hooks\n    rev: 5863e162f1bed1f63eeb716"
  },
  {
    "path": "LICENSE",
    "chars": 35149,
    "preview": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
  },
  {
    "path": "README.md",
    "chars": 4628,
    "preview": "# Readme\n# OMP-运维管理平台\nOMP(Operation Management Platform)是云智慧公司自主设计、研发的轻量级、聚合型、智能运维管理平台。是一款为用户提供便捷运维能力和业务管理的综合平台。具备运维一应俱全"
  },
  {
    "path": "UpdateLog.md",
    "chars": 1984,
    "preview": "# 更新日志\n\n------\n\n\n\n\n\n## v0.1.0 (2021.11.30)\n- 【仪表盘】\n  - 全局状态概览\n  - 当前异常信息展示\n  - 各模块状态展示\n- 【主机管理】\n  - 主机纳管(添加、导入、编辑、维护、删除)"
  },
  {
    "path": "component/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "component/alertmanager/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "component/grafana/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "component/loki/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "component/prometheus/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "config/omp.yaml",
    "chars": 3240,
    "preview": "# 全局用户, 自动解析当前操作用户\nglobal_user: common\n# 初始化时由用户输入本机的ip地址\nlocal_ip: 10.0.1.160\n# SSH执行命令超时时间,单位秒\nssh_cmd_timeout: 60\n# S"
  },
  {
    "path": "config/private_key.pem",
    "chars": 1679,
    "preview": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEAwv4dqlvcYtrPJsCL/VuX0u4FZm2E0du1m01gUnp3afSkx+u2\nGTXptpS7dNfTLguu1HjJUzk"
  },
  {
    "path": "config/product.yaml",
    "chars": 300,
    "preview": "# 使用配置文件的方式更新产品的yaml,留出可更改接口\n# 更新安装参数,如下安装参数在安装过程中会进行更改替换\ninstall:\n  nacos:\n    - name: \"租户类型1单2多3saas\"\n      key: \"depl"
  },
  {
    "path": "config/salt/master",
    "chars": 306,
    "preview": "interface: 0.0.0.0\npublish_port: 19004\nret_port: 19005\nuser: root\nenable_ssh_minions: False\npresence_events: True\nauto_a"
  },
  {
    "path": "config/salt/minion",
    "chars": 155,
    "preview": "master: ${MASTER_IP}\nmaster_port: ${MASTER_PORT}\nuser: ${USER}\nid: ${AGENT_ID}\nroot_dir: ${AGENT_DIR}/data/salt\nconf_fil"
  },
  {
    "path": "config/salt/minion.d/_schedule.conf",
    "chars": 158,
    "preview": "schedule:\n  __mine_interval: {enabled: true, function: mine.update, jid_include: true, maxrunning: 2,\n    minutes: 60, r"
  },
  {
    "path": "config/salt/minion.template",
    "chars": 155,
    "preview": "master: ${MASTER_IP}\nmaster_port: ${MASTER_PORT}\nuser: ${USER}\nid: ${AGENT_ID}\nroot_dir: ${AGENT_DIR}/data/salt\nconf_fil"
  },
  {
    "path": "data/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "data/inspection_file/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "doc/app_publish.md",
    "chars": 12193,
    "preview": "# OMP 社区版-应用商店发布说明文档\n\n[TOC]\n\n## 1. 说明\n\n用户可以在应用商店发布“基础组件”与“应用服务”两个维度的产品,在区分上,应用服务可以理解为完整的提供某一类服务的产品,产品内部可由一个或多个“服务”组成 ,比如"
  },
  {
    "path": "doc/changelogs.md",
    "chars": 424,
    "preview": "## 更新日志\n\nV0.1.0 (2021.11.30)\n\n- 新增功能:\n  【仪表盘】\n  - 全局状态概览\n  - 当前异常信息展示\n  - 各模块状态展示\n  【主机管理】\n  - 主机纳管(添加、导入、编辑、维护、删除)\n  - "
  },
  {
    "path": "logs/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "omp_server/app_store/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "omp_server/app_store/admin.py",
    "chars": 65,
    "preview": "# from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "omp_server/app_store/app_store_filters.py",
    "chars": 3005,
    "preview": "\"\"\"\n应用商店相关过滤器\n\"\"\"\nimport django_filters\nfrom django_filters.rest_framework import FilterSet\n\nfrom db_models.models impor"
  },
  {
    "path": "omp_server/app_store/app_store_serializers.py",
    "chars": 34921,
    "preview": "\"\"\"\n应用商店\n\"\"\"\nimport json\nimport logging\nimport os\nimport time\nfrom django.conf import settings\n\nfrom rest_framework impo"
  },
  {
    "path": "omp_server/app_store/apps.py",
    "chars": 92,
    "preview": "from django.apps import AppConfig\n\n\nclass AppStoreConfig(AppConfig):\n    name = 'app_store'\n"
  },
  {
    "path": "omp_server/app_store/cmd_install_utils.py",
    "chars": 3815,
    "preview": "# -*- coding: utf-8 -*-\n# Project: cmd_install_utils\n# Author: jon.liu@yunzhihui.com\n# Create time: 2022-01-07 15:10\n# I"
  },
  {
    "path": "omp_server/app_store/deploy_mode_utils/__init__.py",
    "chars": 726,
    "preview": "# -*- coding: utf-8 -*-\n# Project: __init__.py\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-11-16 16:44\n# IDE: Py"
  },
  {
    "path": "omp_server/app_store/deploy_mode_utils/base.py",
    "chars": 795,
    "preview": "# -*- coding: utf-8 -*-\n# Project: base\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-11-16 17:10\n# IDE: PyCharm\n#"
  },
  {
    "path": "omp_server/app_store/deploy_mode_utils/even_num.py",
    "chars": 864,
    "preview": "# -*- coding: utf-8 -*-\n# Project: even_num\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-11-23 15:55\n# IDE: PyCha"
  },
  {
    "path": "omp_server/app_store/deploy_mode_utils/mysql.py",
    "chars": 1696,
    "preview": "# -*- coding: utf-8 -*-\n# Project: mysql\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-11-16 16:45\n# IDE: PyCharm\n"
  },
  {
    "path": "omp_server/app_store/deploy_mode_utils/normal.py",
    "chars": 786,
    "preview": "# -*- coding: utf-8 -*-\n# Project: normal\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-11-23 16:06\n# IDE: PyCharm"
  },
  {
    "path": "omp_server/app_store/deploy_mode_utils/odd_num.py",
    "chars": 992,
    "preview": "# -*- coding: utf-8 -*-\n# Project: odd_num\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-11-23 15:55\n# IDE: PyChar"
  },
  {
    "path": "omp_server/app_store/deploy_mode_utils/rocketmq.py",
    "chars": 996,
    "preview": "# -*- coding: utf-8 -*-\n# Project: mysql\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-11-16 16:45\n# IDE: PyCharm\n"
  },
  {
    "path": "omp_server/app_store/deploy_mode_utils/tengine.py",
    "chars": 889,
    "preview": "# -*- coding: utf-8 -*-\n# Project: tengine\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-11-23 16:26\n# IDE: PyChar"
  },
  {
    "path": "omp_server/app_store/deploy_role_utils/__init__.py",
    "chars": 406,
    "preview": "# -*- coding: utf-8 -*-\n# Project: __init__.py\n# Author: jerry.zhang@yunzhihui.com\n# Create time: 2021-12-15 15:46\n# IDE"
  },
  {
    "path": "omp_server/app_store/deploy_role_utils/hadoop.py",
    "chars": 1676,
    "preview": "# -*- coding: utf-8 -*-\n# Project: __init__.py\n# Author: jerry.zhang@yunzhihui.com\n# Create time: 2021-12-16 10:10\n# IDE"
  },
  {
    "path": "omp_server/app_store/deploy_role_utils/mysql.py",
    "chars": 1222,
    "preview": "# -*- coding: utf-8 -*-\n# Project: mysql\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-12-21 20:22\n# IDE: PyCharm\n"
  },
  {
    "path": "omp_server/app_store/deploy_role_utils/redis.py",
    "chars": 727,
    "preview": "# -*- coding: utf-8 -*-\n# Project: __init__.py\n# Author: jerry.zhang@yunzhihui.com\n# Create time: 2021-12-16 10:10\n# IDE"
  },
  {
    "path": "omp_server/app_store/high_availability_utils/__init__.py",
    "chars": 274,
    "preview": "# -*- coding: utf-8 -*-\n# Project: __init__.py\n# Author: jerry.zhang@yunzhihui.com\n# Create time: 2021-12-15 15:46\n# IDE"
  },
  {
    "path": "omp_server/app_store/high_availability_utils/hadoop.py",
    "chars": 11352,
    "preview": "import logging\nimport os\nimport json\nfrom utils.common.exceptions import GeneralError\nfrom db_models.models import (\n   "
  },
  {
    "path": "omp_server/app_store/install_exec.py",
    "chars": 42665,
    "preview": "\"\"\"\n安装执行器\n前提:所有的公共组件都由OMP进行安装处理\n目标:根据数据库中给出的安装记录进行服务安装\n\"\"\"\nimport copy\nimport json\nimport os\nimport time\nimport queue\nim"
  },
  {
    "path": "omp_server/app_store/install_executor.py",
    "chars": 21221,
    "preview": "\"\"\"\n安装执行器\n\"\"\"\nimport os\nimport time\nimport logging\nfrom concurrent.futures import (\n    ThreadPoolExecutor, as_completed"
  },
  {
    "path": "omp_server/app_store/install_utils.py",
    "chars": 31865,
    "preview": "# -*- coding: utf-8 -*-\n# Project: install_utils\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-10-24 14:11\n# IDE: "
  },
  {
    "path": "omp_server/app_store/new_install_serializers.py",
    "chars": 36780,
    "preview": "# -*- coding: utf-8 -*-\n# Project: new_install_serializers\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-11-12 09:"
  },
  {
    "path": "omp_server/app_store/new_install_utils.py",
    "chars": 74173,
    "preview": "# -*- coding: utf-8 -*-\n# Project: new_install_utils\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-11-12 14:01\n# I"
  },
  {
    "path": "omp_server/app_store/new_install_view.py",
    "chars": 13756,
    "preview": "# -*- coding: utf-8 -*-\n# Project: new_install_view\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-11-12 09:19\n# ID"
  },
  {
    "path": "omp_server/app_store/post_install_utils/__init__.py",
    "chars": 339,
    "preview": "# -*- coding: utf-8 -*-\n# Project: __init__.py\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-12-06 11:47\n# IDE: Py"
  },
  {
    "path": "omp_server/app_store/post_install_utils/base.py",
    "chars": 3616,
    "preview": "# -*- coding: utf-8 -*-\n# Project: base\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-12-06 13:58\n# IDE: PyCharm\n#"
  },
  {
    "path": "omp_server/app_store/post_install_utils/nacos.py",
    "chars": 1900,
    "preview": "# -*- coding: utf-8 -*-\n# Project: nacos\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-12-06 11:48\n# IDE: PyCharm\n"
  },
  {
    "path": "omp_server/app_store/post_install_utils/tengine.py",
    "chars": 1848,
    "preview": "# -*- coding: utf-8 -*-\n# Project: tengine\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-12-06 11:47\n# IDE: PyChar"
  },
  {
    "path": "omp_server/app_store/service_splitting.py",
    "chars": 5191,
    "preview": "import json\nimport logging\n\nfrom django.db.models import F\n\nfrom db_models.models import Service, DetailInstallHistory, "
  },
  {
    "path": "omp_server/app_store/tasks.py",
    "chars": 34755,
    "preview": "\"\"\"\n主机相关异步任务\n\"\"\"\n\nimport os\nimport yaml\nimport time\nimport json\nimport redis\nimport logging\n\nfrom celery import shared_t"
  },
  {
    "path": "omp_server/app_store/tmp_exec_back_task.py",
    "chars": 2931,
    "preview": "import os\nfrom utils.parse_config import (\n    OMP_REDIS_PORT, OMP_REDIS_PASSWORD, OMP_REDIS_HOST\n)\nimport time\nfrom app"
  },
  {
    "path": "omp_server/app_store/upload_task.py",
    "chars": 9888,
    "preview": "import os\nfrom db_models.models import ApplicationHub, ProductHub, UploadPackageHistory, Labels\nimport logging\nfrom cele"
  },
  {
    "path": "omp_server/app_store/urls.py",
    "chars": 5605,
    "preview": "# -*- coding: utf-8 -*-\n# Project: urls\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-10-08 15:54\n# IDE: PyCharm\n#"
  },
  {
    "path": "omp_server/app_store/views.py",
    "chars": 42895,
    "preview": "\"\"\"\n应用商店相关视图\n\"\"\"\nimport os\nimport uuid\nimport json\nimport time\nimport string\nimport random\nimport logging\n\nfrom rest_fra"
  },
  {
    "path": "omp_server/app_store/views_for_install.py",
    "chars": 3718,
    "preview": "# -*- coding: utf-8 -*-\n# Project: views_for_install\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-10-21 17:59\n# I"
  },
  {
    "path": "omp_server/backups/__init__.py",
    "chars": 41,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\n"
  },
  {
    "path": "omp_server/backups/admin.py",
    "chars": 41,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\n"
  },
  {
    "path": "omp_server/backups/apps.py",
    "chars": 131,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\n\nfrom django.apps import AppConfig\n\n\nclass BackupsConfig(AppConfig):\n    name ="
  },
  {
    "path": "omp_server/backups/backup_service.py",
    "chars": 6741,
    "preview": "# # -*- coding:utf-8 -*-\n# # Project: backup_service\nimport logging\nimport random\nimport time\nimport json\n\n\"\"\"\nif __name"
  },
  {
    "path": "omp_server/backups/backups_serializers.py",
    "chars": 3682,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\nimport logging\nimport os\nfrom rest_framework.serializers import ModelSerializer"
  },
  {
    "path": "omp_server/backups/backups_utils.py",
    "chars": 6936,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\nimport logging\nimport os\nimport subprocess\nimport tarfile\nimport json\nimport ti"
  },
  {
    "path": "omp_server/backups/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "omp_server/backups/tasks.py",
    "chars": 3015,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\nimport os\nimport time\nimport datetime\nimport logging\n\nfrom celery import shared"
  },
  {
    "path": "omp_server/backups/urls.py",
    "chars": 835,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\n\"\"\"\n备份相关的路由\n\"\"\"\nfrom rest_framework.routers import DefaultRouter\n\nfrom backups."
  },
  {
    "path": "omp_server/backups/views.py",
    "chars": 6636,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\n\nimport logging\n\nfrom rest_framework.mixins import ListModelMixin, CreateModelM"
  },
  {
    "path": "omp_server/db_models/__init__.py",
    "chars": 53,
    "preview": "default_app_config = \"db_models.apps.DbModelsConfig\"\n"
  },
  {
    "path": "omp_server/db_models/admin.py",
    "chars": 65,
    "preview": "# from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "omp_server/db_models/apps.py",
    "chars": 227,
    "preview": "from django.apps import AppConfig\n\n\nclass DbModelsConfig(AppConfig):\n    name = 'db_models'\n\n    def ready(self):\n      "
  },
  {
    "path": "omp_server/db_models/migrations/0001_initial.py",
    "chars": 42018,
    "preview": "# Generated by Django 3.1.4 on 2021-12-01 09:44\n\nimport django.contrib.auth.models\nimport django.contrib.auth.validators"
  },
  {
    "path": "omp_server/db_models/migrations/0002_auto_20211202_1830.py",
    "chars": 540,
    "preview": "# Generated by Django 3.1.4 on 2021-12-02 18:30\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0003_host_init_status.py",
    "chars": 489,
    "preview": "# Generated by Django 3.1.4 on 2021-12-02 19:38\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0004_auto_20211203_1617.py",
    "chars": 1823,
    "preview": "# Generated by Django 3.1.4 on 2021-12-03 16:17\n\nfrom django.db import migrations, models\nimport django.db.models.deleti"
  },
  {
    "path": "omp_server/db_models/migrations/0005_auto_20211206_1723.py",
    "chars": 2115,
    "preview": "# Generated by Django 3.1.4 on 2021-12-06 17:23\n\nfrom django.db import migrations, models\nimport django.db.models.deleti"
  },
  {
    "path": "omp_server/db_models/migrations/0005_update_init_status.py",
    "chars": 503,
    "preview": "# Generated by Django 3.1.4 on 2021-12-03 14:30\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0006_merge_20211206_1833.py",
    "chars": 277,
    "preview": "# Generated by Django 3.1.4 on 2021-12-06 18:33\n\nfrom django.db import migrations\n\n\nclass Migration(migrations.Migration"
  },
  {
    "path": "omp_server/db_models/migrations/0007_deploymentplan.py",
    "chars": 1397,
    "preview": "# Generated by Django 3.1.4 on 2021-12-13 17:14\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0008_service_vip.py",
    "chars": 455,
    "preview": "# Generated by Django 3.1.4 on 2021-12-22 10:20\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0009_auto_20211228_1603.py",
    "chars": 632,
    "preview": "# Generated by Django 3.1.4 on 2021-12-28 16:03\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0010_auto_20220114_1830.py",
    "chars": 6182,
    "preview": "# Generated by Django 3.1.4 on 2022-01-14 18:30\n\nfrom django.conf import settings\nfrom django.db import migrations, mode"
  },
  {
    "path": "omp_server/db_models/migrations/0010_backuphistory_backupsetting.py",
    "chars": 2925,
    "preview": "# Generated by Django 3.1.4 on 2022-01-11 11:01\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0011_auto_20220112_1607.py",
    "chars": 554,
    "preview": "# Generated by Django 3.1.4 on 2022-01-12 16:07\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0012_auto_20220112_1653.py",
    "chars": 666,
    "preview": "# Generated by Django 3.1.4 on 2022-01-12 16:53\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0013_merge_20220114_1838.py",
    "chars": 277,
    "preview": "# Generated by Django 3.1.4 on 2022-01-14 18:38\n\nfrom django.db import migrations\n\n\nclass Migration(migrations.Migration"
  },
  {
    "path": "omp_server/db_models/migrations/0014_auto_20220121_1616.py",
    "chars": 1648,
    "preview": "# Generated by Django 3.1.4 on 2022-01-21 16:16\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0015_executionrecord.py",
    "chars": 1961,
    "preview": "# Generated by Django 3.1.4 on 2022-01-24 17:50\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0016_auto_20220125_1800.py",
    "chars": 433,
    "preview": "# Generated by Django 3.1.4 on 2022-01-25 18:00\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0017_selfhealinghistory_selfhealingsetting.py",
    "chars": 3074,
    "preview": "# Generated by Django 3.1.4 on 2022-01-28 14:50\n\nfrom django.db import migrations, models\nimport django.db.models.deleti"
  },
  {
    "path": "omp_server/db_models/migrations/0018_userloginlog_request_result.py",
    "chars": 482,
    "preview": "# Generated by Django 3.1.4 on 2022-02-08 15:37\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0019_toolexecutedetailhistory_toolexecutemainhistory_toolinfo_uploadfilehistory.py",
    "chars": 7252,
    "preview": "# Generated by Django 3.1.4 on 2022-02-16 11:25\n\nfrom django.conf import settings\nfrom django.db import migrations, mode"
  },
  {
    "path": "omp_server/db_models/migrations/0020_init_tools.py",
    "chars": 283,
    "preview": "# Generated by Django 3.1.4 on 2022-02-22 16:59\n\nfrom django.db import migrations\n\n\nclass Migration(migrations.Migration"
  },
  {
    "path": "omp_server/db_models/migrations/0021_customscript.py",
    "chars": 1709,
    "preview": "# Generated by Django 3.1.4 on 2022-02-23 15:36\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0022_alertrule_rule.py",
    "chars": 2758,
    "preview": "# Generated by Django 3.1.4 on 2022-02-25 09:44\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0023_auto_20220225_1747.py",
    "chars": 1473,
    "preview": "# Generated by Django 3.1.4 on 2022-02-25 17:47\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0024_auto_20220226_1300.py",
    "chars": 991,
    "preview": "# Generated by Django 3.1.4 on 2022-02-27 13:00\nimport os\n\nfrom django.conf import settings\nfrom django.db import migrat"
  },
  {
    "path": "omp_server/db_models/migrations/0025_alertrule_forbidden.py",
    "chars": 412,
    "preview": "# Generated by Django 3.1.4 on 2022-02-28 19:31\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0026_alertrule_hash_data.py",
    "chars": 975,
    "preview": "# Generated by Django 3.1.4 on 2022-03-03 13:28\n\nfrom django.db import migrations, models\nfrom uuid import uuid4\nfrom db"
  },
  {
    "path": "omp_server/db_models/migrations/0026_auto_20220303_1527.py",
    "chars": 1183,
    "preview": "# Generated by Django 3.1.4 on 2022-03-03 15:27\n\nfrom django.db import migrations, models\nimport django.db.models.manage"
  },
  {
    "path": "omp_server/db_models/migrations/0027_merge_20220304_2000.py",
    "chars": 278,
    "preview": "# Generated by Django 3.1.4 on 2022-03-04 20:00\n\nfrom django.db import migrations\n\n\nclass Migration(migrations.Migration"
  },
  {
    "path": "omp_server/db_models/migrations/0028_auto_20220304_2001.py",
    "chars": 1142,
    "preview": "# Generated by Django 3.1.4 on 2022-03-04 20:01\n\nfrom django.db import migrations, models\n\nfrom db_models.models import "
  },
  {
    "path": "omp_server/db_models/migrations/0029_auto_20230110_1739.py",
    "chars": 658,
    "preview": "# Generated by Django 3.1.4 on 2023-01-10 17:39\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/0030_auto_20230711_1739.py",
    "chars": 2906,
    "preview": "# Generated by Django 3.1.4 on 2023-05-11 09:33\n\nimport django.core.validators\nfrom django.db import migrations, models\n"
  },
  {
    "path": "omp_server/db_models/migrations/0031_auto_20230921_1128.py",
    "chars": 3099,
    "preview": "# Generated by Django 3.1.4 on 2023-09-21 11:28\n\nfrom django.db import migrations, models\n\n\nclass Migration(migrations.M"
  },
  {
    "path": "omp_server/db_models/migrations/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "omp_server/db_models/mixins.py",
    "chars": 1584,
    "preview": "\"\"\"\n模型混入类\n\"\"\"\nfrom django.db import models\n\n\nclass TimeStampMixin(models.Model):\n    \"\"\" 创建、更新时间混入类 \"\"\"\n\n    created = m"
  },
  {
    "path": "omp_server/db_models/models/__init__.py",
    "chars": 2367,
    "preview": "from .backup import BackupSetting, BackupHistory, BackupCustom\nfrom .email import EmailSMTPSetting, ModuleSendEmailSetti"
  },
  {
    "path": "omp_server/db_models/models/backup.py",
    "chars": 2328,
    "preview": "import os\n\nfrom django.db import models\n\nfrom db_models.mixins import TimeStampMixin\n\n\nclass BackupCustom(models.Model):"
  },
  {
    "path": "omp_server/db_models/models/custom_metric.py",
    "chars": 1318,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\n# Author:' Lingyang.guo'\n# CreateDate: 14:08\nimport os\n\nfrom django.db import m"
  },
  {
    "path": "omp_server/db_models/models/email.py",
    "chars": 5921,
    "preview": "import logging\nimport os\n\nimport requests\nfrom django.db import models\nfrom ruamel import yaml\n\nfrom .monitor import Ale"
  },
  {
    "path": "omp_server/db_models/models/env.py",
    "chars": 367,
    "preview": "from django.db import models\n\n\nclass Env(models.Model):\n    \"\"\" 环境表 \"\"\"\n\n    objects = None\n    name = models.CharField("
  },
  {
    "path": "omp_server/db_models/models/execution.py",
    "chars": 1823,
    "preview": "from django.db import models\nfrom db_models.mixins import TimeStampMixin\n\n\nclass ModuleChoices(models.TextChoices):\n    "
  },
  {
    "path": "omp_server/db_models/models/host.py",
    "chars": 4559,
    "preview": "from django.db import models\n\nfrom db_models.mixins import TimeStampMixin, DeleteMixin\nfrom .env import Env\n\n\nclass Host"
  },
  {
    "path": "omp_server/db_models/models/inspection.py",
    "chars": 4358,
    "preview": "import os\n\nfrom django.db import models\n\nfrom .env import Env\n\n\nclass InspectionHistory(models.Model):\n    \"\"\"巡检记录历史表\"\"\""
  },
  {
    "path": "omp_server/db_models/models/install.py",
    "chars": 6908,
    "preview": "from django.db import models\n\nfrom db_models.mixins import TimeStampMixin\nfrom .service import Service\n\n\nclass MainInsta"
  },
  {
    "path": "omp_server/db_models/models/monitor.py",
    "chars": 5426,
    "preview": "from django.db import models\n\nfrom .env import Env\n\n\nclass MonitorUrl(models.Model):\n    \"\"\" 用户操作记录表 \"\"\"\n\n    objects = "
  },
  {
    "path": "omp_server/db_models/models/product.py",
    "chars": 7329,
    "preview": "from django.db import models\n\nfrom db_models.mixins import TimeStampMixin, DeleteMixin\n\n\nclass Labels(models.Model):\n   "
  },
  {
    "path": "omp_server/db_models/models/self_heal.py",
    "chars": 2326,
    "preview": "from django.db import models\nfrom django.core.validators import MaxValueValidator\n\n\nclass WaitSelfHealing(models.Model):"
  },
  {
    "path": "omp_server/db_models/models/service.py",
    "chars": 12799,
    "preview": "import json\nimport os\n\nfrom django.db import models\n\nfrom db_models.mixins import TimeStampMixin, DeleteMixin\nfrom utils"
  },
  {
    "path": "omp_server/db_models/models/threshold.py",
    "chars": 5022,
    "preview": "import hashlib\nfrom uuid import uuid4\nfrom django.db import models\n\n\n\nclass HostThreshold(models.Model):\n    \"\"\"主机阈值设置表\""
  },
  {
    "path": "omp_server/db_models/models/tool.py",
    "chars": 10065,
    "preview": "# -*- coding: utf-8 -*-\n# Project: tools\n# Author: jon.liu@yunzhihui.com\n# Create time: 2022-02-08 16:04\n# IDE: PyCharm\n"
  },
  {
    "path": "omp_server/db_models/models/upgrade.py",
    "chars": 5420,
    "preview": "from django.db import models\n\nfrom .product import ApplicationHub\nfrom .env import Env\nfrom .service import Service\nfrom"
  },
  {
    "path": "omp_server/db_models/models/upload.py",
    "chars": 3505,
    "preview": "import os\nimport random\nimport string\nfrom datetime import datetime\n\nfrom django.conf import settings\nfrom django.core.f"
  },
  {
    "path": "omp_server/db_models/models/user.py",
    "chars": 2060,
    "preview": "from django.contrib.auth.models import AbstractUser\nfrom django.db import models\n\n\nclass UserProfile(AbstractUser):\n    "
  },
  {
    "path": "omp_server/db_models/receivers/__init__.py",
    "chars": 295,
    "preview": "from .execution_record import install_execution_record,\\\n    upgrade_execution_record, rollback_execution_record\nfrom .s"
  },
  {
    "path": "omp_server/db_models/receivers/execution_record.py",
    "chars": 1523,
    "preview": "from django.dispatch import receiver\nfrom django.db.models.signals import post_save\n\nfrom db_models.models import Execut"
  },
  {
    "path": "omp_server/db_models/receivers/service.py",
    "chars": 3603,
    "preview": "from django.db.models.signals import pre_delete, post_save\nfrom django.dispatch import receiver\n\nfrom db_models.mixins i"
  },
  {
    "path": "omp_server/db_models/signals/__init__.py",
    "chars": 14,
    "preview": "__all__ = [\n]\n"
  },
  {
    "path": "omp_server/dev_code.md",
    "chars": 198,
    "preview": "# 项目及研发规范\n\n## 前后端接口规范\n\n### 后端正确响应返回格式\n```json\n{\n  \"code\": 0,\n  \"message\": \"success\",\n  \"data\": null\n}\n```\n\n### 后端错误响应返回格"
  },
  {
    "path": "omp_server/dev_requirement.txt",
    "chars": 1601,
    "preview": "amqp==5.0.6\nasgiref==3.4.1\naspy.yaml==1.3.0\nattrs==21.2.0\nbackports.entry-points-selectable==1.1.0\nbcrypt==3.2.0\nbilliar"
  },
  {
    "path": "omp_server/hosts/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "omp_server/hosts/admin.py",
    "chars": 65,
    "preview": "# from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "omp_server/hosts/apps.py",
    "chars": 85,
    "preview": "from django.apps import AppConfig\n\n\nclass HostsConfig(AppConfig):\n    name = 'hosts'\n"
  },
  {
    "path": "omp_server/hosts/hosts_filters.py",
    "chars": 610,
    "preview": "\"\"\"\n主机相关过滤器\n\"\"\"\nimport django_filters\nfrom django_filters.rest_framework import FilterSet\n\nfrom db_models.models import "
  },
  {
    "path": "omp_server/hosts/hosts_serializers.py",
    "chars": 21466,
    "preview": "\"\"\"\n主机序列化器\n\"\"\"\nimport logging\nimport socket\nimport struct\nfrom concurrent.futures import (\n    ThreadPoolExecutor, as_co"
  },
  {
    "path": "omp_server/hosts/tasks.py",
    "chars": 20513,
    "preview": "# -*- coding: utf-8 -*-\n# Project: tasks\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-09-12 11:54\n# IDE: PyCharm\n"
  },
  {
    "path": "omp_server/hosts/urls.py",
    "chars": 1755,
    "preview": "# -*- coding: utf-8 -*-\n# Project: urls\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-09-12 11:44\n# IDE: PyCharm\n#"
  },
  {
    "path": "omp_server/hosts/views.py",
    "chars": 12048,
    "preview": "\"\"\"\n主机相关视图\n\"\"\"\nimport logging\nfrom django.db import transaction\n\nfrom rest_framework.viewsets import GenericViewSet\nfrom"
  },
  {
    "path": "omp_server/inspection/__init__.py",
    "chars": 108,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\n# Author: len chen\n# CreateDate: 2021/10/13 6:00 下午\n# Description:\n"
  },
  {
    "path": "omp_server/inspection/admin.py",
    "chars": 153,
    "preview": "from django.contrib import admin\n\n# Register your models here.\n\nfrom db_models.models import InspectionHistory\n\nadmin.si"
  },
  {
    "path": "omp_server/inspection/apps.py",
    "chars": 95,
    "preview": "from django.apps import AppConfig\n\n\nclass InspectionConfig(AppConfig):\n    name = 'inspection'\n"
  },
  {
    "path": "omp_server/inspection/filters.py",
    "chars": 1630,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\n# Author: len chen\n# CreateDate: 2021/10/13 9:02 下午\n# Description: 巡检查询\nimport "
  },
  {
    "path": "omp_server/inspection/get_prometheus_risk_data.py",
    "chars": 2245,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\n# Author: len chen\n# CreateDate: 2021/11/8 11:53 上午\n# Description:\nfrom db_mode"
  },
  {
    "path": "omp_server/inspection/get_service_topology.py",
    "chars": 619,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\n# Author: len chen\n# CreateDate: 2021/11/8 2:04 下午\n# Description:\n\nfrom db_mode"
  },
  {
    "path": "omp_server/inspection/inspection_utils.py",
    "chars": 5451,
    "preview": "import logging\nimport traceback\n\nfrom db_models.models import InspectionHistory, InspectionReport\nfrom inspection.joint_"
  },
  {
    "path": "omp_server/inspection/joint_json_report.py",
    "chars": 1472,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\n# Author: len chen\n# CreateDate: 2021/10/25 10:30 上午\n# Description:\n\n\ndef joint"
  },
  {
    "path": "omp_server/inspection/serializers.py",
    "chars": 776,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\n# Author: len chen\n# CreateDate: 2021/10/13 8:36 下午\n# Description: 巡检序列化\nfrom r"
  },
  {
    "path": "omp_server/inspection/tasks.py",
    "chars": 8487,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\n# Author: len chen\n# CreateDate: 2021/10/13 6:06 下午\n# Description: 巡检异步任务及定时任务\n"
  },
  {
    "path": "omp_server/inspection/urls.py",
    "chars": 942,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\n# Author: len chen\n# CreateDate: 2021/10/13 8:52 下午\n# Description: 巡检 路由\nfrom r"
  },
  {
    "path": "omp_server/inspection/views.py",
    "chars": 12723,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\n# Author: len chen\n# CreateDate: 2021/10/13 6:06 下午\n# Description: 巡检视图\nimport "
  },
  {
    "path": "omp_server/manage.py",
    "chars": 666,
    "preview": "#!/usr/bin/env python\n\"\"\"Django's command-line utility for administrative tasks.\"\"\"\nimport os\nimport sys\n\n\ndef main():\n "
  },
  {
    "path": "omp_server/omp_server/__init__.py",
    "chars": 219,
    "preview": "# This will make sure the app is always imported when\n# Django starts so that shared_task will use this app.\nimport pymy"
  },
  {
    "path": "omp_server/omp_server/asgi.py",
    "chars": 397,
    "preview": "\"\"\"\nASGI config for omp_server project.\n\nIt exposes the ASGI callable as a module-level variable named ``application``.\n"
  },
  {
    "path": "omp_server/omp_server/celery.py",
    "chars": 1067,
    "preview": "# -*- coding: utf-8 -*-\n# Project: celery\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-09-12 11:30\n# IDE: PyCharm"
  },
  {
    "path": "omp_server/omp_server/settings.py",
    "chars": 10362,
    "preview": "\"\"\"\nDjango settings for omp_server project.\n\nGenerated by 'django-admin startproject' using Django 3.1.4.\n\nFor more info"
  },
  {
    "path": "omp_server/omp_server/urls.py",
    "chars": 2825,
    "preview": "\"\"\"omp_server URL Configuration\n\nThe `urlpatterns` list routes URLs to views. For more information please see:\n    https"
  },
  {
    "path": "omp_server/omp_server/wsgi.py",
    "chars": 397,
    "preview": "\"\"\"\nWSGI config for omp_server project.\n\nIt exposes the WSGI callable as a module-level variable named ``application``.\n"
  },
  {
    "path": "omp_server/promemonitor/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "omp_server/promemonitor/admin.py",
    "chars": 63,
    "preview": "from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "omp_server/promemonitor/alert_util.py",
    "chars": 9562,
    "preview": "import datetime\nimport logging\nimport traceback\n\nimport pytz\nfrom omp_server.settings import TIME_ZONE\nfrom db_models.mo"
  },
  {
    "path": "omp_server/promemonitor/alertmanager.py",
    "chars": 6207,
    "preview": "import json\nimport logging\nfrom datetime import datetime, timedelta\nfrom db_models.models import MonitorUrl\nfrom utils.p"
  },
  {
    "path": "omp_server/promemonitor/apps.py",
    "chars": 156,
    "preview": "from django.apps import AppConfig\n\n\nclass PromemonitorConfig(AppConfig):\n    default_auto_field = 'django.db.models.BigA"
  },
  {
    "path": "omp_server/promemonitor/custom_script_serializers.py",
    "chars": 710,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\n# Author:' Lingyang.guo'\n# CreateDate: 14:26\nimport json\n\nfrom rest_framework i"
  },
  {
    "path": "omp_server/promemonitor/custom_script_views.py",
    "chars": 12102,
    "preview": "# !/usr/bin/python3\n# -*-coding:utf-8-*-\n# Author:' Lingyang.guo'\n# CreateDate: 14:08\nimport json\nimport logging\nimport "
  },
  {
    "path": "omp_server/promemonitor/grafana_url.py",
    "chars": 10561,
    "preview": "from db_models.models import GrafanaMainPage, MonitorUrl, Host, ApplicationHub, Service\nimport requests\nimport json\nimpo"
  },
  {
    "path": "omp_server/promemonitor/grafana_views.py",
    "chars": 3753,
    "preview": "# -*- coding: utf-8 -*-\n# Project: grafana_views\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-10-12 10:27\n# IDE: "
  },
  {
    "path": "omp_server/promemonitor/promemonitor_filters.py",
    "chars": 2174,
    "preview": "\"\"\"\n主机相关过滤器\n\"\"\"\nimport time\n\nimport django_filters\nfrom django_filters.rest_framework import FilterSet\n\nfrom db_models.m"
  },
  {
    "path": "omp_server/promemonitor/promemonitor_serializers.py",
    "chars": 9786,
    "preview": "import datetime\nimport logging\n\nfrom django.db.models import F\nfrom rest_framework import serializers\nfrom rest_framewor"
  },
  {
    "path": "omp_server/promemonitor/prometheus.py",
    "chars": 30958,
    "preview": "import json\nimport logging\nimport math\n\nimport requests\n\nfrom db_models.models import MonitorUrl\nfrom utils.parse_config"
  },
  {
    "path": "omp_server/promemonitor/prometheus_utils.py",
    "chars": 32177,
    "preview": "# -*- coding: utf-8 -*-\n# Project: prometheus_utils\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-10-11 14:31\n# ID"
  },
  {
    "path": "omp_server/promemonitor/tasks.py",
    "chars": 2038,
    "preview": "# -*- coding: utf-8 -*-\n# Project: tasks\n# Author: jon.liu@yunzhihui.com\n# Create time: 2021-10-09 09:17\n# IDE: PyCharm\n"
  },
  {
    "path": "omp_server/promemonitor/urls.py",
    "chars": 2668,
    "preview": "\"\"\"\n监控相关的路由\n\"\"\"\nfrom rest_framework.routers import DefaultRouter\n\nfrom promemonitor.custom_script_views import CustomScr"
  },
  {
    "path": "omp_server/promemonitor/views.py",
    "chars": 43415,
    "preview": "# Create your views here.\n\"\"\"\n监控相关视图\n\"\"\"\nimport json\nimport logging\nimport traceback\n\nimport requests\nfrom django.core.v"
  },
  {
    "path": "omp_server/service_upgrade/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "omp_server/service_upgrade/admin.py",
    "chars": 63,
    "preview": "from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "omp_server/service_upgrade/apps.py",
    "chars": 104,
    "preview": "from django.apps import AppConfig\n\n\nclass ServiceUpgradeConfig(AppConfig):\n    name = 'service_upgrade'\n"
  },
  {
    "path": "omp_server/service_upgrade/filters.py",
    "chars": 418,
    "preview": "from rest_framework.filters import BaseFilterBackend\n\n\nclass RollBackHistoryFilter(BaseFilterBackend):\n\n    def filter_q"
  },
  {
    "path": "omp_server/service_upgrade/handler/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "omp_server/service_upgrade/handler/base.py",
    "chars": 7339,
    "preview": "import logging\nimport time\nfrom datetime import datetime\nfrom functools import reduce\n\nfrom django.conf import settings\n"
  },
  {
    "path": "omp_server/service_upgrade/handler/rollback_handler.py",
    "chars": 6976,
    "preview": "import logging\nimport os\nimport random\nimport time\nfrom datetime import datetime\n\nfrom django.conf import settings\nfrom "
  },
  {
    "path": "omp_server/service_upgrade/handler/upgrade_handler.py",
    "chars": 8656,
    "preview": "import json\nimport logging\nimport os\nimport random\nfrom datetime import datetime\n\nfrom django.conf import settings\nfrom "
  },
  {
    "path": "omp_server/service_upgrade/serializers.py",
    "chars": 10833,
    "preview": "from rest_framework import serializers\nfrom rest_framework.exceptions import ValidationError\n\nfrom db_models.mixins impo"
  },
  {
    "path": "omp_server/service_upgrade/tasks.py",
    "chars": 8937,
    "preview": "import logging\nimport time\nfrom concurrent.futures import ThreadPoolExecutor, as_completed, wait, \\\n    ALL_COMPLETED\n\nf"
  },
  {
    "path": "omp_server/service_upgrade/update_data_json.py",
    "chars": 6013,
    "preview": "import json\nimport os\n\nfrom django.conf import settings\n\nfrom db_models.models import DetailInstallHistory, Service, Hos"
  },
  {
    "path": "omp_server/service_upgrade/urls.py",
    "chars": 1086,
    "preview": "from django.urls import path\n\nfrom service_upgrade.views import UpgradeChoiceMaxVersionListAPIView, \\\n    UpgradeHistory"
  },
  {
    "path": "omp_server/service_upgrade/views.py",
    "chars": 15955,
    "preview": "import json\nimport logging\nimport traceback\n\nfrom django.db import models, transaction\nfrom rest_framework.filters impor"
  },
  {
    "path": "omp_server/services/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "omp_server/services/admin.py",
    "chars": 65,
    "preview": "# from django.contrib import admin\n\n# Register your models here.\n"
  },
  {
    "path": "omp_server/services/app_check/__init__.py",
    "chars": 123,
    "preview": "from .conf_check import ConfCheck\nfrom .manage_ser_exec import ManagerService\n\n__all__ = [\n    ConfCheck, ManagerService"
  },
  {
    "path": "omp_server/services/app_check/conf_check.py",
    "chars": 18845,
    "preview": "import time\nimport logging\nimport json\nimport random\n\nfrom concurrent.futures import (\n    ThreadPoolExecutor, as_comple"
  },
  {
    "path": "omp_server/services/app_check/manage_ser_exec.py",
    "chars": 13898,
    "preview": "import json\nimport os\nimport copy\nimport logging\nimport time\nfrom django.db import transaction\nfrom db_models.models imp"
  },
  {
    "path": "omp_server/services/apps.py",
    "chars": 91,
    "preview": "from django.apps import AppConfig\n\n\nclass ServicesConfig(AppConfig):\n    name = 'services'\n"
  },
  {
    "path": "omp_server/services/permission.py",
    "chars": 455,
    "preview": "from django.conf import settings\nfrom rest_framework.permissions import BasePermission\n\n\nclass GetDataJsonAuthenticated("
  },
  {
    "path": "omp_server/services/self_heal_filter.py",
    "chars": 1348,
    "preview": "import time\nimport django_filters\nfrom db_models.models import SelfHealingHistory\nfrom django_filters.rest_framework imp"
  },
  {
    "path": "omp_server/services/self_heal_serializers.py",
    "chars": 1650,
    "preview": "import logging\n\nfrom rest_framework import serializers\nfrom rest_framework.serializers import ModelSerializer, Serialize"
  },
  {
    "path": "omp_server/services/self_heal_util.py",
    "chars": 1442,
    "preview": "import logging\nimport requests\nimport json\nfrom utils.parse_config import MONITOR_PORT\nfrom promemonitor.prometheus_util"
  },
  {
    "path": "omp_server/services/self_heal_view.py",
    "chars": 2737,
    "preview": "import logging\nimport json\n\nfrom django_filters.rest_framework import DjangoFilterBackend\nfrom rest_framework.filters im"
  },
  {
    "path": "omp_server/services/self_healing.py",
    "chars": 13647,
    "preview": "import logging\nimport copy\nimport time\nimport paramiko\nimport requests\nimport json\nimport datetime\nfrom db_models.models"
  }
]

// ... and 459 more files (download for full content)

About this extraction

This page contains the full source code of the CloudWise-OpenSource/OMP GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 659 files (6.1 MB), approximately 1.6M tokens, and a symbol index with 4568 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!