Modified agent in order to make it more failure tolerant

This commit is contained in:
Vladimir Kozhukalov
2013-01-31 16:16:43 +04:00
committed by default
parent 6ca35fa0c7
commit 8ea9c0c2a0
7 changed files with 138 additions and 137 deletions

View File

@@ -143,51 +143,56 @@ class NodeAgent
def _detailed
detailed_meta = {
:System => {
:Manufacturer => _manufacturer,
:Serial => _serial,
:Product => _product_name,
:Family => (@os[:dmi][:system][:family] or "Unknown"),
:Version => (@os[:dmi][:system][:version] or "Unknown"),
:system => {
:manufacturer => _manufacturer,
:serial => _serial,
:product => _product_name,
:family => (@os[:dmi][:system][:family] rescue nil),
:version => (@os[:dmi][:system][:version] rescue nil),
},
:Interfaces => [],
:Cpu => {
:Total => @os[:cpu][:total],
:Real => @os[:cpu][:real],
:Spec => [],
:interfaces => [],
:cpu => {
:total => (@os[:cpu][:total] rescue nil),
:real => (@os[:cpu][:real] rescue nil),
:spec => [],
},
:Disks => [],
:Memory => _real_memory,
:disks => [],
:memory => _real_memory,
}
@os[:network][:interfaces].each do |int, intinfo|
intinfo[:addresses].each do |addr, addrinfo|
if addrinfo[:family] =~ /lladdr/
detailed_meta[:Interfaces] << {
:Name => int,
:Mac => addr
(@os[:network][:interfaces] or {} rescue {}).each do |int, intinfo|
(intinfo[:addresses] or {} rescue {}).each do |addr, addrinfo|
if (addrinfo[:family] rescue nil) =~ /lladdr/
detailed_meta[:interfaces] << {
:name => int,
:mac => addr
}
end
end
end
@os[:cpu].each do |cpu, cpuinfo|
if cpu =~ /^[\d]+/
detailed_meta[:Cpu][:Spec] << {
:Mhz => cpuinfo[:mhz].to_i.to_s,
:Model => cpuinfo[:model_name].gsub(/ +/, " ")
(@os[:cpu] or {} rescue {}).each do |cpu, cpuinfo|
if cpu =~ /^[\d]+/ and cpuinfo
detailed_meta[:cpu][:spec] << {
# .to_i.to_s is applied in order to round to integer
:mhz => (cpuinfo[:mhz].to_i.to_s rescue nil),
:model => (cpuinfo[:model_name].gsub(/ +/, " ") rescue nil)
}
end
end
@os[:block_device].each do |bname, binfo|
if bname =~ /^(sd|hd|vd)./
block_size = `cat /sys/block/#{bname}/queue/logical_block_size`
detailed_meta[:Disks] << {
:Name => bname,
:Model => binfo[:model],
# 512 bytes is the size of one sector by default
# 1000000000 bytes is 1 Gb
:Size => (binfo[:size].to_i * block_size.to_i).to_s,
(@os[:block_device] or {} rescue {}).each do |bname, binfo|
if bname =~ /^(sd|hd|vd)./ and binfo
# 512 bytes is the size of one sector by default
block_size = 512
block_size = `cat /sys/block/#{bname}/queue/logical_block_size`.to_i if $?.to_i == 0
detailed_meta[:disks] << {
:name => bname,
:model => binfo[:model],
:size => (binfo[:size].to_i * block_size).to_s,
}
end
end
detailed_meta
end
@@ -202,38 +207,39 @@ class NodeAgent
else
# Check in other place for VBox: ohai doesn't show it's virtual with VBox 4.2.4
return "VBOX" if @os["dmi"]["system"]["product_name"] == "VirtualBox" rescue nil
return @os[:dmi][:system][:manufacturer] rescue "Unknown"
return @os[:dmi][:system][:manufacturer] rescue nil
end
end
def _product_name
if _is_virtual
@os["virtualization"]["role"] rescue "Unknown"
@os["virtualization"]["role"] rescue nil
else
@os[:dmi][:system][:product_name] rescue "Unknown"
@os[:dmi][:system][:product_name] rescue nil
end
end
def _serial
@os[:dmi][:system][:serial_number] rescue "Unknown"
@os[:dmi][:system][:serial_number] rescue nil
end
def _real_memory
dmi = `dmidecode`
return nil if $?.to_i != 0
mem_mapped = false
dmi.each do |line|
mem_mapped = true if /^Memory Array Mapped Address$/.match(line)
if /^\s*Range Size:\s+(\d+)\s+(mb|gb|kb)/i.match(line) and mem_mapped
size, unit = $1, $2
size, unit = $1.to_i, $2
case unit
when /^kb$/i
return (size.to_i * 1024).to_s
return (size * 1024).to_s
when /^mb$/i
return (size.to_i * 1048576).to_s
return (size * 1048576).to_s
when /^gb$/i
return (size.to_i * 1073741824).to_s
return (size * 1073741824).to_s
end
mem_mapped = false
nil
end
end
end
@@ -299,6 +305,8 @@ rescue Exception => e
end
agent = NodeAgent.new(logger, url)
puts JSON.pretty_generate agent._detailed
exit 0
agent.update_state
post_res = agent.post

View File

@@ -12,7 +12,7 @@ from nailgun.api.handlers.base import JSONHandler
class NodeHandler(JSONHandler):
fields = ('id', 'name', 'info', 'network_data', 'role', 'progress',
fields = ('id', 'name', 'meta', 'network_data', 'role', 'progress',
'status', 'mac', 'fqdn', 'ip', 'manufacturer', 'platform_name',
'pending_addition', 'pending_deletion', 'os_platform',
'error_type')
@@ -85,13 +85,14 @@ class NodeCollectionHandler(JSONHandler):
node.name = "Untitled (%s)" % data['mac'][-5:]
orm().add(node)
orm().commit()
ram = "Unknown"
if 'Memory' in node.info and node.info['Memory']:
ram = round(int(node.info['Memory']) / 1073741824, 1)
cores = node.info.get('Cpu', {}).get('Total', "Unknown")
try:
ram = round(int(node.meta['memory']) / 1073741824, 1)
except (KeyError, TypeError):
ram = "unknown"
cores = node.meta.get('cpu', {}).get('total', "unknown")
notifier.notify("discover",
"New node with %s CPU core(s) "
"and %s memory is discovered" %
"and %s GB memory is discovered" %
(cores, ram), node_id=node.id)
raise web.webapi.created(json.dumps(
NodeHandler.render(node),

View File

@@ -174,7 +174,7 @@ class Node(Base, BasicValidator):
cluster_id = Column(Integer, ForeignKey('clusters.id'))
name = Column(Unicode(100))
status = Column(Enum(*NODE_STATUSES), nullable=False, default='discover')
meta = Column(JSON)
meta = Column(JSON, default={})
mac = Column(String(17), nullable=False, unique=True)
ip = Column(String(15))
fqdn = Column(String(255))
@@ -211,10 +211,6 @@ class Node(Base, BasicValidator):
def needs_redeletion(self):
return self.status == 'error' and self.error_type == 'deletion'
@property
def info(self):
return self.meta or {}
@classmethod
def validate(cls, data):
d = cls.validate_json(data)

View File

@@ -12,45 +12,45 @@
"mac": "C0:8D:DF:52:76:F1",
"ip": "10.0.12.45",
"meta": {
"Interfaces": [
{
"Mac": "C0:8D:DF:52:76:F1",
"Name": "eth0"
},
{
"Mac": "C0:8D:DF:52:76:F2",
"Name": "eth1"
}
],
"Cpu": {
"Real": 1,
"Spec": [
{
"Mhz": "1200",
"Model": "Intel(R) Core(TM)2 Duo CPU T6570 @ 2.10GHz"
},
{
"Mhz": "2101",
"Model": "Intel(R) Core(TM)2 Duo CPU T6570 @ 2.10GHz"
}
],
"Total": 2
},
"Disks": [
{
"Size": "320072933376",
"Model": "TOSHIBA MK3259GS",
"Name": "sda"
}
],
"Memory": "8589934592",
"System": {
"Product": "QWERTY",
"Family": "Not Specified",
"Manufacturer": "Dell",
"Serial": "123456",
"Version": "Not Specified"
"disks": [
{
"size": "320072933376",
"model": "TOSHIBA MK3259GS",
"name": "sda"
}
],
"interfaces": [
{
"mac": "52:54:00:96:81:6E",
"name": "eth0"
},
{
"mac": "C8:0A:A9:A6:FF:28",
"name": "eth1"
}
],
"cpu": {
"total": 2,
"real": 1,
"spec": [
{
"mhz": "1200",
"model": "Intel(R) Core(TM)2 Duo CPU T6570 @ 2.10GHz"
},
{
"mhz": "1200",
"model": "Intel(R) Core(TM)2 Duo CPU T6570 @ 2.10GHz"
}
]
},
"memory": 8589934592,
"system": {
"version": "Power Edge 2970",
"manufacturer": "Dell",
"product": "QWERTY",
"serial": "123456",
"family": "Power Edge"
}
}
}
},

View File

@@ -159,8 +159,8 @@ class FakeDeletionThread(FakeThread):
for node in nodes_to_restore:
orm.add(node)
orm.commit()
ram = round(node.info.get('ram') or 0, 1)
cores = node.info.get('cores') or 'unknown'
ram = round(node.meta.get('ram') or 0, 1)
cores = node.meta.get('cores') or 'unknown'
notifier.notify("discover",
"New node with %s CPU core(s) "
"and %s GB memory is discovered" %

View File

@@ -48,60 +48,56 @@ class BaseHandlers(TestCase):
"Content-Type": "application/json"
}
flush()
for fxtr in self.fixtures:
self.upload_fixtures(self.fixtures)
def fxtr_paths_by_names(self, fxtr_names):
for fxtr in fxtr_names:
fxtr_path = os.path.join(
self.fixture_dir,
"%s.json" % fxtr
)
if not os.path.exists(fxtr_path):
logging.warning(
"Fixture file not found: %s",
"Fixture file was not found: %s",
fxtr_path
)
break
else:
logging.info(
"Uploading fixture from file: %s",
logging.debug(
"Fixture file is found, yielding path: %s",
fxtr_path
)
with open(fxtr_path, "r") as fixture:
upload_fixture(fixture)
yield fxtr_path
def upload_fixtures(self, fxtr_names):
for fxtr_path in self.fxtr_paths_by_names(fxtr_names):
with open(fxtr_path, "r") as fxtr_file:
upload_fixture(fxtr_file)
def read_fixtures(self, fxtr_names):
data = []
for fxtr_path in self.fxtr_paths_by_names(fxtr_names):
with open(fxtr_path, "r") as fxtr_file:
try:
data.extend(json.load(fxtr_file))
except:
logging.error(
"Error occured while loading "
"fixture %s" % fxtr_path
)
return data
def find_item_by_pk_model(self, data, pk, model):
for item in data:
if item.get('pk') == pk and item.get('model') == model:
return item
def default_metadata(self):
metadata = {
"Interfaces": [
{
"Mac": "C0:8D:DF:52:76:F1",
"Name": "eth0"
}
],
"Cpu": {
"Real": 1,
"Spec": [
{
"Mhz": "1200",
"Model": "Intel(R) Core(TM)2 Duo CPU T6570 @ 2.10GHz"
}
],
"Total": 1
},
"Disks": [
{
"Size": "320072933376",
"Model": "TOSHIBA MK3259GS",
"Name": "sda"
}
],
"Memory": "8589934592",
"System": {
"Product": "QWERTY",
"Family": "Not Specified",
"Manufacturer": "Dell",
"Serial": "123456",
"Version": "Not Specified"
}
}
return metadata
item = self.find_item_by_pk_model(
self.read_fixtures(("sample_environment",)),
1, 'nailgun.node')
return item.get('fields').get('meta')
def _generate_random_mac(self):
mac = [randint(0x00, 0x7f) for _ in xrange(6)]

View File

@@ -27,11 +27,11 @@ class TestHandlers(BaseHandlers):
node.pending_deletion, response['pending_deletion'])
self.assertEquals(node.status, response['status'])
self.assertEquals(
node.info['Cpu']['Total'],
response['info']['Cpu']['Total']
node.meta['cpu']['total'],
response['meta']['cpu']['total']
)
self.assertEquals(node.info['Disks'], response['info']['Disks'])
self.assertEquals(node.info['Memory'], response['info']['Memory'])
self.assertEquals(node.meta['disks'], response['meta']['disks'])
self.assertEquals(node.meta['memory'], response['meta']['memory'])
def test_node_creation_with_id(self):
node_id = '080000000003'