class Aio::DeviceManager # 保存所有设备类 # devices = {"device_name" => device_klass} attr_accessor :devices # 按设备型号保存cmd # cmds = {"device_type" => [module_klass1, module_klass2]} attr_accessor :cmds # 命令的正则表达式匹配 # cmds_reg = {module_klass => ["device_type", "cmd_reg"]} attr_accessor :cmds_reg # 警告信息汇总类 attr_reader :warning_summarize # 模块管理信息,只读 attr_accessor :module_manager # 当初始化完成,所有cmd模块已经整理完毕 def initialize(module_manager) self.cmds = {} self.cmds_reg = {} self.devices = {} @module_manager = module_manager @warning_summarize = Aio::Warning::WarningSummarize.new(self) tidy_cmds end def []=(key, val) @devices[key] = val end def [](key) @devices[key] end # 设备台数 def devices_number self.devices.keys.size end def inspect total = devices_number names = [] each_devices do |name, klass| names << name end "#" end # 整理cmds 和 cmds_reg # 返回为Hash = {"cisco" => [klass, klass]} def tidy_cmds device_type = @module_manager.get_modules_device_type_to_s device_type.each do |type| # 整理cmds type_modules = @module_manager.get_modules_by_device_type(type) self.cmds[type] = type_modules # 整理cmds_reg type_modules.each do |cmd_klass| # 将cmd_short转变为正则表达式 # 相同的cmd_short会导致重复 cmd_short_reg = Aio::Base::Toolkit::Regexp.to_reg(cmd_klass.cmd_short) cmds_reg[cmd_klass] = [type, cmd_short_reg] end end return cmds end # 仅仅返回各个命令的正则表达式的数组,在input/console中使用 def just_cmds_reg res = [] cmds_reg.each_pair do |klass, info| res << info[1] end return res end def each_devices devices.each_pair do |device_name, device_klass| yield device_name, device_klass end end def each_devices_with_index i = 0 devices.each_pair do |device_name, device_klass| yield device_name, device_klass, i i += 1 end end # 轮询设备名以及有用信息 def each_devices_with_useful each_devices do |device_name, device_klass| useful = device_klass.cmds_useful yield device_name, useful end end # 只返回按照特定的设备,types 为数组 def each_devices_of(*types) each_devices do |name, klass| next unless types.include? klass.device_type yield klass end end # 返回只是cisco的设备 def each_devices_of_cisco each_devices do |name, klass| next unless klass.device_type == 'cisco' yield klass end end # 返回只是h3c的设备 def each_devices_of_h3c each_devices do |name, klass| next unless klass.device_type == 'h3c' yield klass end end # 返回只是maipu的设备 def each_devices_of_maipu each_devices do |name, klass| next unless klass.device_type == 'maipu' yield klass end end # 判断设备名是否存在 def device_exist?(opts={}) each_devices do |devices, _| if devices == opts[:device_name] return true end end return false end # 设备类型分类 # 返回 { "cisco" => [device_name1, ...] } def device_type_classify res = {} each_devices do |device_name, device_klass| type = device_klass.device_type unless res.has_key?(type) res[type] = [] end res[type] << device_name end return res end # 查找是否有符合指定的cmd模块 # 有可能两种设备类型同时存在同样的命令,在不确定设备类型的情况下,全部输出 # 注意此处输出的样式为 res = [ [device_type, cmd_klass], ... ] # info = { cmd_klass => [type, cmd_reg] } def cmd_module_assign(opts) cmd = opts[:cmd] res = [] device_type = opts[:device_type] cmds_reg.each do |cmd_klass, info| reg = info[1] type = info[0] if reg.match(cmd) # 判断如果没有指定device_type,那么全部输出 # 如果指定,则只输出指定类型 # cmd_klass 会被覆盖, 已经修复 if device_type == type res << [type, cmd_klass.division] elsif device_type.nil? res << [type, cmd_klass.division] end end end return res.empty? ? nil : res end # 在状态机中使用了,添加设备,并添加cmd-context def add_device(opts) # 判断是否已经有了device,如果有,则沿用,如果没有则新建 if has_device?(opts) device_klass = self.devices[opts[:device_name]] else device_klass = Aio::Device::ParentDevice.new device_klass.device_name = opts[:device_name] end # cmd 和 context 必须同时存在的情况下才能加载的 if opts[:cmd] and opts[:context] cmd_arr = cmd_module_assign(opts) if cmd_arr.nil? device_klass.add_cmd_context_by_cmd_name( opts[:cmd], opts[:context] ) elsif cmd_arr.size == 1 device_klass.add_cmd_context_by_klass( cmd_arr[0], opts[:context] ) else # 有多个cmd模块的情况,全部依次加进去,但是最后分析的时候,出现明显问题的将被删除 cmd_arr.each do |cmd_klass| device_klass.add_cmd_context_by_klass( cmd_klass, opts[:context] ) end end end self.devices[opts[:device_name]] = device_klass end # 将compare中得到的warning信息合并到各个设备的warning_klass中 def merge_warning(info) # info = { # cm1: [ [device_name, cmd, str], .. ], # cm2: [ [device_name, cmd, str], .. ] # } info.each_pair do |key, element| element.each do |e| name = e.shift # e = [cmd, match_str_info] self[name].warning_klass.warning_compare({cm: key, e: e}) end end end # 整理汇总警告信息 def warning_summarize_tidy @warning_summarize.tidy_warning end # 是否已经有device_name def has_device?(opts) self.devices.has_key?(opts[:device_name]) end end