<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                [TOC] ## **一、自定義admin的actions** 需要有專門的審批員來審批新資產,對資產的合法性、健全性、可用性等更多方面進行審核,如果沒有問題,那么就批準上線。 <br /> 批準上線這一操作是通過admin的自定義actions來實現的。 Django的admin默認有一個delete操作的action,所有在admin中的模型都有這個action,更多的就需要我們自己編寫了。 ![](https://img.kancloud.cn/68/9d/689dba08264283abc283774828058323_1240x469.png) 修改`/assets/admin.py`的代碼,新的代碼如下: ~~~ from django.contrib import admin # Register your models here. from assets import models from assets import asset_handler class NewAssetAdmin(admin.ModelAdmin): list_display = ['asset_type', 'sn', 'model', 'manufacturer', 'c_time', 'm_time'] list_filter = ['asset_type', 'manufacturer', 'c_time'] search_fields = ('sn',) actions = ['approve_selected_new_assets'] def approve_selected_new_assets(self, request, queryset): # 獲得被打鉤的checkbox對應的資產 selected = request.POST.getlist(admin.ACTION_CHECKBOX_NAME) success_upline_number = 0 for asset_id in selected: obj = asset_handler.ApproveAsset(request, asset_id) ret = obj.asset_upline() if ret: success_upline_number += 1 # 頂部綠色提示信息 self.message_user(request, "成功批準 %s 條新資產上線!" % success_upline_number) approve_selected_new_assets.short_description = "批準選擇的新資產" class AssetAdmin(admin.ModelAdmin): list_display = ['asset_type', 'name', 'status', 'approved_by', 'c_time', "m_time"] admin.site.register(models.Asset, AssetAdmin) admin.site.register(models.Server) admin.site.register(models.StorageDevice) admin.site.register(models.SecurityDevice) admin.site.register(models.BusinessUnit) admin.site.register(models.Contract) admin.site.register(models.CPU) admin.site.register(models.Disk) admin.site.register(models.EventLog) admin.site.register(models.IDC) admin.site.register(models.Manufacturer) admin.site.register(models.NetworkDevice) admin.site.register(models.NIC) admin.site.register(models.RAM) admin.site.register(models.Software) admin.site.register(models.Tag) admin.site.register(models.NewAssetApprovalZone, NewAssetAdmin) ~~~ 說明: * 通過`actions = ['approve_selected_new_assets']`定義當前模型的新acitons列表; * `approve_selected_new_assets()`方法包含具體的動作邏輯; * 自定義的action接收至少三個參數,第一個是self,第二個是request即請求,第三個是被選中的數據對象集合queryset。 * 首先通過`request.POST.getlist()`方法獲取被打鉤的checkbox對應的資產; * 注意:django3.0后,`ACTION_CHECKBOX_NAME`的位置發生了改變。所以需要改成`admin.helpers.ACTION_CHECKBOX_NAME`或者`'_selected_action'`。 * 可能同時有多個資產被選擇,所以這是個批量操作,需要進行循環; * selected是一個包含了被選中資產的id值的列表; * 對于每一個資產,創建一個`asset_handler.ApproveAsset()`的實例,然后調用實例的`asset_upline()`方法,并獲取返回值。如果返回值為True,說明該資產被成功批準,那么`success_upline_number`變量+1,保存成功批準的資產數; * 最后,在admin中給與提示信息。 * `approve_selected_new_assets.short_description = "批準選擇的新資產"`用于在admin界面中為action提供中文顯示。你可以嘗試去掉這條,看看效果。 <br /> 重新啟動CMDB,進入admin的待審批資產區,查看上方的acitons動作條,如下所示: ![](https://img.kancloud.cn/06/d3/06d3a631c920edf71717a277b84916e4_1240x474.png) <br /> ## **二、創建測試用例** 由于沒有真實的服務器供測試,這里需要手動創建一些虛假的服務器用例,方便后面的使用和展示。 首先,將先前的所有資產條目全部從admin中刪除,確保數據庫內沒有任何數據。 然后,在Client/bin/目錄下新建一個`report_assets`腳本,其內容如下: <br /> <details> <summary>report_assets</summary> ``` # -*- coding:utf-8 -*- import json import urllib.request import urllib.parse import os import sys BASE_DIR = os.path.dirname(os.getcwd()) # 設置工作目錄,使得包和模塊能夠正常導入 sys.path.append(BASE_DIR) from conf import settings def update_test(data): """ 創建測試用例 :return: """ # 將數據打包到一個字典內,并轉換為json格式 data = {"asset_data": json.dumps(data)} # 根據settings中的配置,構造url url = "http://%s:%s%s" % (settings.Params['server'], settings.Params['port'], settings.Params['url']) print('正在將數據發送至: [%s] ......' % url) try: # 使用Python內置的urllib.request庫,發送post請求。 # 需要先將數據進行封裝,并轉換成bytes類型 data_encode = urllib.parse.urlencode(data).encode() response = urllib.request.urlopen(url=url, data=data_encode, timeout=settings.Params['request_timeout']) print("\033[31;1m發送完畢!\033[0m ") message = response.read().decode() print("返回結果:%s" % message) except Exception as e: message = "發送失敗" print("\033[31;1m發送失敗,%s\033[0m" % e) if __name__ == '__main__': windows_data = { "os_type": "Windows", "os_release": "7 64bit 6.1.7601 ", "os_distribution": "Microsoft", "asset_type": "server", "cpu_count": 2, "cpu_model": "Intel(R) Core(TM) i5-2300 CPU @ 2.80GHz", "cpu_core_count": 8, "ram": [ { "slot": "A1", "capacity": 8, "model": "Physical Memory", "manufacturer": "kingstone ", "sn": "456" }, ], "manufacturer": "Intel", "model": "P67X-UD3R-B3", "wake_up_type": 6, "sn": "00426-OEM-8992662-111111", "physical_disk_driver": [ { "iface_type": "unknown", "slot": 0, "sn": "3830414130423230343234362020202020202020", "model": "KINGSTON SV100S264G ATA Device", "manufacturer": "(標準磁盤驅動器)", "capacity": 128 }, { "iface_type": "SATA", "slot": 1, "sn": "383041413042323023234362020102020202020", "model": "KINGSTON SV100S264G ATA Device", "manufacturer": "(標準磁盤驅動器)", "capacity": 2048 }, ], "nic": [ { "mac": "14:CF:22:FF:48:34", "model": "[00000011] Realtek RTL8192CU Wireless LAN 802.11n USB 2.0 Network Adapter", "name": 11, "ip_address": "192.168.1.110", "net_mask": [ "255.255.255.0", "64" ] }, { "mac": "0A:01:27:00:00:00", "model": "[00000013] VirtualBox Host-Only Ethernet Adapter", "name": 13, "ip_address": "192.168.56.1", "net_mask": [ "255.255.255.0", "64" ] }, { "mac": "14:CF:22:FF:48:34", "model": "[00000017] Microsoft Virtual WiFi Miniport Adapter", "name": 17, "ip_address": "", "net_mask": "" }, { "mac": "14:CF:22:FF:48:34", "model": "Intel Adapter", "name": 17, "ip_address": "192.1.1.1", "net_mask": "" }, ] } linux_data = { "asset_type": "server", "manufacturer": "innotek GmbH", "sn": "00001", "model": "VirtualBox", "uuid": "E8DE611C-4279-495C-9B58-502B6FCED076", "wake_up_type": "Power Switch", "os_distribution": "Ubuntu", "os_release": "Ubuntu 16.04.3 LTS", "os_type": "Linux", "cpu_count": "2", "cpu_core_count": "4", "cpu_model": "Intel(R) Core(TM) i5-2300 CPU @ 2.80GHz", "ram": [ { "slot": "A1", "capacity": 8, } ], "ram_size": 3.858997344970703, "nic": [], "physical_disk_driver": [ { "model": "VBOX HARDDISK", "size": "50", "sn": "VBeee1ba73-09085302" } ] } update_test(linux_data) update_test(windows_data) ``` </details> <br /> 該腳本的作用很簡單,人為虛構了兩臺服務器(一臺windows,一臺Linux)的信息,并發送給CMDB。單獨執行該腳本,在admin的新資產待審批區可以看到添加了兩條新資產信息。 <br /> 要添加更多的資產,只需修改腳本中`windows_data`和`linux_data`的數據即可。但是要注意的是,如果不修改sn,那么會變成資產數據更新,而不是增加新資產,這一點一定要注意。 <br /> OK,我們再加兩條資產,這樣就變成四個實例了。 ![](https://img.kancloud.cn/47/b2/47b2553b70f5685e3ce48aed5169d9a8_1240x633.png) <br /> ## **三、批準資產上線** 有已經忍不住點擊‘執行’命令的請舉手! 是不是出現了錯誤? ~~~ AttributeError at /admin/assets/newassetapprovalzone/ module 'assets.asset_handler' has no attribute 'ApproveAsset' ~~~ 這是必然的,因為還沒有寫如何上線的代碼啊! 在`/assets/asset_handler.py`中添加下面的代碼: <br /> <details> <summary>/assets/asset_handler.py</summary> ``` def log(log_type, msg=None, asset=None, new_asset=None, request=None): """ 記錄日志 """ event = models.EventLog() if log_type == "upline": event.name = "%s <%s> : 上線" % (asset.name, asset.sn) event.asset = asset event.detail = "資產成功上線!" event.user = request.user elif log_type == "approve_failed": event.name = "%s <%s> : 審批失敗" % (new_asset.asset_type, new_asset.sn) event.new_asset = new_asset event.detail = "審批失敗!\n%s" % msg event.user = request.user # 更多日志類型..... event.save() class ApproveAsset: """ 審批資產并上線。 """ def __init__(self, request, asset_id): self.request = request self.new_asset = models.NewAssetApprovalZone.objects.get(id=asset_id) self.data = json.loads(self.new_asset.data) def asset_upline(self): # 為以后的其它類型資產擴展留下接口 func = getattr(self, "_%s_upline" % self.new_asset.asset_type) ret = func() return ret def _server_upline(self): # 在實際的生產環境中,下面的操作應該是原子性的整體事務,任何一步出現異常,所有操作都要回滾。 asset = self._create_asset() # 創建一條資產并返回資產對象。注意要和待審批區的資產區分開。 try: self._create_manufacturer(asset) # 創建廠商 self._create_server(asset) # 創建服務器 self._create_CPU(asset) # 創建CPU self._create_RAM(asset) # 創建內存 self._create_disk(asset) # 創建硬盤 self._create_nic(asset) # 創建網卡 self._delete_original_asset() # 從待審批資產區刪除已審批上線的資產 except Exception as e: asset.delete() log('approve_failed', msg=e, new_asset=self.new_asset, request=self.request) print(e) return False else: # 添加日志 log("upline", asset=asset, request=self.request) print("新服務器上線!") return True def _create_asset(self): """ 創建資產并上線 :return: """ # 利用request.user自動獲取當前管理人員的信息,作為審批人添加到資產數據中。 asset = models.Asset.objects.create(asset_type=self.new_asset.asset_type, name="%s: %s" % (self.new_asset.asset_type, self.new_asset.sn), sn=self.new_asset.sn, approved_by=self.request.user, ) return asset def _create_manufacturer(self, asset): """ 創建廠商 :param asset: :return: """ # 判斷廠商數據是否存在。如果存在,看看數據庫里是否已經有該廠商,再決定是獲取還是創建。 m = self.new_asset.manufacturer if m: manufacturer_obj, _ = models.Manufacturer.objects.get_or_create(name=m) asset.manufacturer = manufacturer_obj asset.save() def _create_server(self, asset): """ 創建服務器 :param asset: :return: """ models.Server.objects.create(asset=asset, model=self.new_asset.model, os_type=self.new_asset.os_type, os_distribution=self.new_asset.os_distribution, os_release=self.new_asset.os_release, ) def _create_CPU(self, asset): """ 創建CPU. 教程這里對發送過來的數據采取了最大限度的容忍, 實際情況下你可能還要對數據的完整性、合法性、數據類型進行檢測, 根據不同的檢測情況,是被動接收,還是打回去要求重新收集,請自行決定。 這里的業務邏輯非常復雜,不可能面面俱到。 :param asset: :return: """ cpu = models.CPU.objects.create(asset=asset) cpu.cpu_model = self.new_asset.cpu_model cpu.cpu_count = self.new_asset.cpu_count cpu.cpu_core_count = self.new_asset.cpu_core_count cpu.save() def _create_RAM(self, asset): """ 創建內存。通常有多條內存 :param asset: :return: """ ram_list = self.data.get('ram') if not ram_list: # 萬一一條內存數據都沒有 return for ram_dict in ram_list: if not ram_dict.get('slot'): raise ValueError("未知的內存插槽!") # 使用虛擬機的時候,可能無法獲取內存插槽,需要你修改此處的邏輯。 ram = models.RAM() ram.asset = asset ram.slot = ram_dict.get('slot') ram.sn = ram_dict.get('sn') ram.model = ram_dict.get('model') ram.manufacturer = ram_dict.get('manufacturer') ram.capacity = ram_dict.get('capacity', 0) ram.save() def _create_disk(self, asset): """ 存儲設備種類多,還有Raid情況,需要根據實際情況具體解決。 這里只以簡單的SATA硬盤為例子。可能有多塊硬盤。 :param asset: :return: """ disk_list = self.data.get('physical_disk_driver') if not disk_list: # 一條硬盤數據都沒有 return for disk_dict in disk_list: if not disk_dict.get('sn'): raise ValueError("未知sn的硬盤!") # 根據sn確定具體某塊硬盤。 disk = models.Disk() disk.asset = asset disk.sn = disk_dict.get('sn') disk.model = disk_dict.get('model') disk.manufacturer = disk_dict.get('manufacturer'), disk.slot = disk_dict.get('slot') disk.capacity = disk_dict.get('capacity', 0) iface = disk_dict.get('interface_type') if iface in ['SATA', 'SAS', 'SCSI', 'SSD', 'unknown']: disk.interface_type = iface disk.save() def _create_nic(self, asset): """ 創建網卡。可能有多個網卡,甚至虛擬網卡。 :param asset: :return: """ nic_list = self.data.get("nic") if not nic_list: return for nic_dict in nic_list: if not nic_dict.get('mac'): raise ValueError("網卡缺少mac地址!") if not nic_dict.get('model'): raise ValueError("網卡型號未知!") nic = models.NIC() nic.asset = asset nic.name = nic_dict.get('name') nic.model = nic_dict.get('model') nic.mac = nic_dict.get('mac') nic.ip_address = nic_dict.get('ip_address') if nic_dict.get('net_mask'): if len(nic_dict.get('net_mask')) > 0: nic.net_mask = nic_dict.get('net_mask')[0] nic.save() def _delete_original_asset(self): """ 這里的邏輯是已經審批上線的資產,就從待審批區刪除。 也可以設置為修改成已審批狀態但不刪除,只是在管理界面特別處理,不讓再次審批,灰色顯示。 不過這樣可能導致待審批區越來越大。 :return: """ self.new_asset.delete() ``` </details> <br /> 核心就是增加了一個記錄日志的log()函數以及審批資產的ApproveAsset類。 log()函數很簡單,根據日志類型的不同,保存日志需要的各種信息,比如日志名稱、關聯的資產對象、日志詳細內容和審批人員等等。所有的日志都被保存在數據庫中,可以在admin中查看。 對于關鍵的ApproveAsset類,說明如下: * 初始化方法接收reqeust和待審批資產的id; * 分別提前獲取資產對象和所有數據data; * `asset_upline()`是入口方法,通過反射,獲取一個類似`_server_upline`的方法。之所以這么做,是為后面的網絡設別、安全設備、存儲設備等更多類型資產的審批留下擴展接口。本教程里只實現了服務器類型資產的審批方法,更多的請自行完善,過程基本類似。 `_server_upline()`是服務器類型資產上線的核心方法: * 它首先新建了一個Asset資產對象(注意要和待審批區的資產區分開); * 然后利用該對象,分別創建了對應的廠商、服務器、CPU、內存、硬盤和網卡,并刪除待審批區的對應資產; * 在實際的生產環境中,上面的操作應該是原子性的整體事務,任何一步出現異常,所有操作都要回滾; * 如果任何一步出現錯誤,上面的操作全部撤銷,也就是`asset.delete()`。記錄錯誤日志,返回False; * 如果沒問題,那么記錄正確日志,返回True。 <br /> 對于`_create_asset(self)`方法,利用`request.user`自動獲取當前管理人員的信息,作為審批人添加到資產數據中。 <br /> 對于`_create_manufacturer(self, asset)`方法,先判斷廠商數據是否存在,再決定是獲取還是創建。 <br /> 對于`_create_CPU(self, asset)`等方法,教程這里對數據采取了最大限度的容忍,實際情況下你可能還要對數據的完整性、合法性、數據類型進行檢測,根據不同的檢測情況,是被動接收,還是打回去要求重新收集,請自行決定。這里的業務邏輯非常復雜,不可能面面俱到。后面的內存、硬盤和網卡也是一樣的。 <br /> 對于`_delete_original_asset(self)`方法,這里的邏輯是已經審批上線的資產,就從待審批區刪除。也可以設置為修改成已審批狀態但不刪除,只是在管理界面特別處理,不讓再次審批,灰色顯示,不過這樣可能導致待審批區越來越大。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看