From tashi-dev-returnamber38@example.com Tue Apr 07 18:22:07 2009 Return-Path: <tashi-dev-returnamber38@example.com> Delivered-To: amber38@example.com Received: (qmail 25600 invoked from network); 7 Apr 2009 18:22:07 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (83.161.120.155) by minotaur.apache.org with SMTP; 7 Apr 2009 18:22:07 -0000 Received: (qmail 97882 invoked by uid 500); 7 Apr 2009 18:22:07 -0000 Delivered-To: amber38@example.com Received: (qmail 97859 invoked by uid 500); 7 Apr 2009 18:22:07 -0000 Mailing-List: contact amber38@example.com; run by ezmlm Precedence: bulk List-Help: <mailto:amber38@example.com> List-Unsubscribe: <mailto:amber38@example.com> List-Post: <mailto:amber38@example.com> List-Id: <tashi-dev.incubator.apache.org> Reply-To: amber38@example.com Delivered-To: mailing list amber38@example.com Received: (qmail 97849 invoked by uid 99); 7 Apr 2009 18:22:07 -0000 Received: from nike.apache.org (HELO nike.apache.org) (83.161.120.155) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 07 Apr 2009 18:22:07 +0000 X-ASF-Spam-Status: No, hits=-4.0 required=10.0 tests=RCVD_IN_DNSWL_MED,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: local policy) Received: from [83.161.120.155] (HELO mga09.intel.com) (83.161.120.155) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 07 Apr 2009 18:21:59 +0000 Received: from orsmga001.jf.intel.com ([83.161.120.155]) by orsmga102.jf.intel.com with ESMTP; 07 Apr 2009 11:12:47 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.39,338,1235980800"; d="scan'208";a="504384641" Received: from rrsmsx603.amr.corp.intel.com ([83.161.120.155]) by orsmga001.jf.intel.com with ESMTP; 07 Apr 2009 11:21:05 -0700 Received: from rrsmsx503.amr.corp.intel.com ([83.161.120.155]) by rrsmsx603.amr.corp.intel.com ([83.161.120.155]) with mapi; Tue, 7 Apr 2009 12:21:36 -0600 From: "Ryan, Michael P" <amber38@example.com> To: "amber38@example.com" <amber38@example.com> Date: Tue, 7 Apr 2009 12:21:35 -0600 Subject: Monthly Report Thread-Topic: Monthly Report Thread-Index: Acm3ra88Z5SVjLNwTJa3q6J9TLZq4A== Message-ID: <amber38@example.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: acceptlanguage: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-Virus-Checked: Checked by ClamAV on apache.org Comments? I've posted this on the wiki already, but if changes need to be = made, let me know. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D 2009-April Tashi Incubator Status Report Tashi has been incubating since September 2008. The Tashi project aims to build a software infrastructure for=20 cloud computing on massive internet-scale datasets (what we call=20 Big Data). The idea is to build a cluster management system=20 that enables the Big Data that are stored in a cluster/data center=20 to be accessed, shared, manipulated, and computed on by remote users=20 in a convenient, efficient, and safe manner. Development activities have included adding support for using a database to= =20 track virtual machine information, modifying code to work with Python 2.4,= =20 integration with dynamic DHCP and DNS servers, and adding a "tidy" target t= o=20 check the source code. There have been a few questions on amber38@example.com that centered around=20 getting Tashi up and running. Additionally, submissions on the dev list=20 included patches from a student at CMU, and some scripts from a non-committ= amber38@example.com. There is still a lot of work to be done in growing a community. Items to be resolved before graduation: * Put more effort into project documentation so that other potential=20 contributors may more easily get involved * Develop community diversity (currently Intel and CMU committers) * Prepare and review a release candidate= From tashi-dev-returnamber38@example.com Wed Apr 08 13:53:32 2009 Return-Path: <tashi-dev-returnamber38@example.com> Delivered-To: amber38@example.com Received: (qmail 52394 invoked from network); 8 Apr 2009 13:53:32 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (83.161.120.155) by minotaur.apache.org with SMTP; 8 Apr 2009 13:53:32 -0000 Received: (qmail 34844 invoked by uid 500); 8 Apr 2009 13:53:32 -0000 Delivered-To: amber38@example.com Received: (qmail 34820 invoked by uid 500); 8 Apr 2009 13:53:32 -0000 Mailing-List: contact amber38@example.com; run by ezmlm Precedence: bulk List-Help: <mailto:amber38@example.com> List-Unsubscribe: <mailto:amber38@example.com> List-Post: <mailto:amber38@example.com> List-Id: <tashi-dev.incubator.apache.org> Reply-To: amber38@example.com Delivered-To: mailing list amber38@example.com Received: (qmail 34810 invoked by uid 99); 8 Apr 2009 13:53:32 -0000 Received: from athena.apache.org (HELO athena.apache.org) (83.161.120.155) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 08 Apr 2009 13:53:32 +0000 X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (athena.apache.org: domain of amber38@example.com designates 83.161.120.155 as permitted sender) Received: from [83.161.120.155] (HELO mail-gx0-f170.google.com) (83.161.120.155) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 08 Apr 2009 13:53:23 +0000 Received: by gxk18 with SMTP id 18so230935gxk.12 for <amber38@example.com>; Wed, 08 Apr 2009 06:53:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:sender:received:in-reply-to :references:date:x-google-sender-auth:message-id:subject:from:to :content-type:content-transfer-encoding; bh=ojGy10laPL6takDTcsMHMLCrtDLg5DFy57pxae/YCJo=; b=qz57Wka+JjVMswwc9uQxAvbSpEewS5/6y/pBwu40fiuSNx/zV1pMJ8YekdnKjAOk1L UyuJcuFhghvl8mHW0/VkBG17Eo9hvSUhvBPae2UEy0nvfYuJt7QuT/gbM8/qKqMS1XMO tBOanCDCdMNlcf2cJNmS65FAlXIH6PDwmgtRI= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:sender:in-reply-to:references:date :x-google-sender-auth:message-id:subject:from:to:content-type :content-transfer-encoding; b=X4dKoXcV8J+YRGVr3k0ernHV6pjQnLMk99WqLXgw8lbjxQlMkO/h6K4fP4b+MF+H01 qJ7C71P41vq+rgxSPuk6QT4/0ycRgto/1/uCEsWI7EIpO1yvfcqLNEsFI+PwN0FCdM44 cPtCbr7nA4a5UUVj43tYr6tuxB/9un/mipvWA= MIME-Version: 1.0 Sender: amber38@example.com Received: by 83.161.120.155 with SMTP id u14mr2511103ybd.170.1239198782600; Wed, 08 Apr 2009 06:53:02 -0700 (PDT) In-Reply-To: <amber38@example.com> References: <amber38@example.com> Date: Wed, 8 Apr 2009 09:53:02 -0400 X-Google-Sender-Auth: 57e5902d59aa8c0a Message-ID: <amber38@example.com> Subject: Re: Monthly Report From: "David O'Hallaron" <amber38@example.com> To: amber38@example.com Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-Virus-Checked: Checked by ClamAV on apache.org looks good. On Tue, Apr 7, 2009 at 2:21 PM, Ryan, Michael P <amber38@example.com> wrote: > Comments? =A0I've posted this on the wiki already, but if changes need to= be made, let me know. > > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D > > 2009-April Tashi Incubator Status Report > > Tashi has been incubating since September 2008. > > The Tashi project aims to build a software infrastructure for > cloud computing on massive internet-scale datasets (what we call > Big Data). The idea is to build a cluster management system > that enables the Big Data that are stored in a cluster/data center > to be accessed, shared, manipulated, and computed on by remote users > in a convenient, efficient, and safe manner. > > Development activities have included adding support for using a database = to > track virtual machine information, modifying code to work with Python 2.4= , > integration with dynamic DHCP and DNS servers, and adding a "tidy" target= to > check the source code. > > There have been a few questions on amber38@example.com that centered around > getting Tashi up and running. =A0Additionally, submissions on the dev lis= t > included patches from a student at CMU, and some scripts from a non-commi= tter > at Intel. =A0There is still a lot of work to be done in growing a communi= ty. > > Items to be resolved before graduation: > =A0 =A0 =A0 =A0* Put more effort into project documentation so that other= potential > =A0 =A0 =A0 =A0 =A0contributors may more easily get involved > =A0 =A0 =A0 =A0* Develop community diversity (currently Intel and CMU com= mitters) > =A0 =A0 =A0 =A0* Prepare and review a release candidate --=20 -- David O'Hallaron -- Director, Intel Research Pittsburgh -- Assoc Prof of CS and ECE, Carnegie Mellon University -- http://www.cs.cmu.edu/~droh From tashi-dev-returnamber38@example.com Tue Apr 14 19:34:31 2009 Return-Path: <tashi-dev-returnamber38@example.com> Delivered-To: amber38@example.com Received: (qmail 36257 invoked from network); 14 Apr 2009 19:34:31 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (83.161.120.155) by minotaur.apache.org with SMTP; 14 Apr 2009 19:34:31 -0000 Received: (qmail 38154 invoked by uid 500); 14 Apr 2009 19:34:31 -0000 Delivered-To: amber38@example.com Received: (qmail 38120 invoked by uid 500); 14 Apr 2009 19:34:31 -0000 Mailing-List: contact amber38@example.com; run by ezmlm Precedence: bulk List-Help: <mailto:amber38@example.com> List-Unsubscribe: <mailto:amber38@example.com> List-Post: <mailto:amber38@example.com> List-Id: <tashi-dev.incubator.apache.org> Reply-To: amber38@example.com Delivered-To: mailing list amber38@example.com Received: (qmail 38110 invoked by uid 99); 14 Apr 2009 19:34:31 -0000 Received: from nike.apache.org (HELO nike.apache.org) (83.161.120.155) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 14 Apr 2009 19:34:31 +0000 X-ASF-Spam-Status: No, hits=1.2 required=10.0 tests=SPF_NEUTRAL X-Spam-Check-By: apache.org Received-SPF: neutral (nike.apache.org: local policy) Received: from [83.161.120.155] (HELO smtp.andrew.cmu.edu) (83.161.120.155) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 14 Apr 2009 19:34:24 +0000 Received: from CMU-255281.WV.CC.CMU.EDU (CMU-255281.WV.CC.CMU.EDU [83.161.120.155]) (user=jcipar mech=PLAIN (0 bits)) by smtp.andrew.cmu.edu (8.14.3/8.13.8) with ESMTP id n3EJXpRx022359 (version=TLSv1/SSLv3 cipher=AES128-SHA bits=128 verify=NOT) for <amber38@example.com>; Tue, 14 Apr 2009 15:33:51 -0400 Message-Id: <amber38@example.com> From: Jim Cipar <amber38@example.com> To: amber38@example.com In-Reply-To: <amber38@example.com> Content-Type: text/plain; charset=US-ASCII; format=flowed; delsp=yes Content-Transfer-Encoding: 7bit Mime-Version: 1.0 (Apple Message framework v930.3) Subject: Locality server Date: Tue, 14 Apr 2009 15:33:50 -0400 References: <amber38@example.com> X-Mailer: Apple Mail (2.930.3) X-PMX-Version: 83.161.120.1556731, Antispam-Engine: 83.161.120.1556912, Antispam-Data: 283.161.120.155541 X-SMTP-Spam-Clean: 8% (BODY_SIZE_10000_PLUS 0, TO_NO_NAME 0, __CP_MEDIA_BODY 0, __CT 0, __CTE 0, __CT_TEXT_PLAIN 0, __HAS_MSGID 0, __HAS_X_MAILER 0, __MIME_TEXT_ONLY 0, __MIME_VERSION 0, __MSGID_APPLEMAIL 0, __SANE_MSGID 0, __TO_MALFORMED_2 0) X-SMTP-Spam-Score: 8% X-Scanned-By: MIMEDefang 2.60 on 83.161.120.155 X-Virus-Checked: Checked by ClamAV on apache.org I've been working on the Tashi locality server. It exports a service that will give the hop count between any set of nodes that it knows about. This can be used by, e.g., an HDFS Client that is running in a VM, to determine which node to read data from. This case requires modifying the HDFS client code, but it is an example of how something like this could be useful. The only call exported right now is: list <list <float>> getHopCountMatrix(list <string>sources, list <string> destinations) This returns the complete hop count matrix between sources and destinations, with positive infinity for any nodes that are either unknown, or not connected. It gathers information about static network objects from a configuration file describing all adjacent things (nodes, switches ...) in the network. Each line of the file has one source, and any number of destinations. For instance, a simple cluster with one top level switch, and two switches each with two hosts might be configured like this: toplevel switch1 switch2 switch1 toplevel host1 host2 switch2 toplevel host3 host4 All physical objects on the network are configured via the configuration file. Information about currently running Tashi VMs, is automatically gathered from the Tashi Cluster Manager, and these are added to the graph. Lastly, there is a script ( src/utils/getLocality.py ) that can be used to contact this service. The script takes two lines of input on stdin: a whitespace separated list of sources, and a whitespace separated list of destinations. It then prints the distance matrix with a row for each source, and a column for each destination. It then waits for two more lines of input on stdin. It will continue until it receives an EOF on stdin. Here's the patch: Index: trunk/src/utils/getLocality.py =================================================================== --- trunk/src/utils/getLocality.py (revision 0) +++ trunk/src/utils/getLocality.py (revision 0) @@ -0,0 +1,53 @@ +#!/usr/bin/python + +import sys +import os +from os import system + +import tashi.services.layoutlocality.localityservice as localityservice + +from thrift import Thrift +from thrift.transport import TSocket +from thrift.transport import TTransport +from thrift.protocol import TBinaryProtocol + +from tashi.util import getConfig + +(config, configFiles) = getConfig(["Client"]) +host = config.get('LocalityService', 'host') +port = int(config.get('LocalityService', 'port')) + +socket = TSocket.TSocket(host, port) +transport = TTransport.TBufferedTransport(socket) +protocol = TBinaryProtocol.TBinaryProtocol(transport) +client = localityservice.Client(protocol) +transport.open() + + +while True: + line1 = "\n" + line2 = "\n" + while line1 != "": + line1 = sys.stdin.readline() + if line1 == "": + sys.exit(0) + if line1 != "\n": + break + line1 = line1.strip() + while line2 != "": + line2 = sys.stdin.readline() + if line2 == "": + sys.exit(0) + if line2 != "\n": + break + line2 = line2.strip() + + sources = line1.split(" ") + destinations = line2.split(" ") + + mat = client.getHopCountMatrix(sources, destinations) + for r in mat: + for c in r: + print '%f\t'%c, + print '\n', + print '\n', Property changes on: trunk/src/utils/getLocality.py ___________________________________________________________________ Added: svn:executable + * Index: trunk/src/tashi/nodemanager/vmcontrol/xenpv.py =================================================================== --- trunk/src/tashi/nodemanager/vmcontrol/xenpv.py (revision 764908) +++ trunk/src/tashi/nodemanager/vmcontrol/xenpv.py (working copy) @@ -156,9 +156,9 @@ image, macAddr, memory, cores): fn = os.path.join("/tmp", vmName) cfgstr = """ -# kernel="/boot/vmlinuz-2.6.24-17-xen" -# ramdisk="/boot/initrd.img-2.6.24-17-xen" -bootloader="/usr/bin/pygrub" +kernel="/boot/vmlinuz-2.6.24-17-xen" +ramdisk="/boot/initrd.img-2.6.24-17-xen" +# bootloader="/usr/bin/pygrub" disk=['tap:qcow:%s,xvda1,w'] vif = [ 'mac=%s' ] # vif = ['ip=83.161.120.155'] Index: trunk/src/tashi/thrift/build.py =================================================================== --- trunk/src/tashi/thrift/build.py (revision 764908) +++ trunk/src/tashi/thrift/build.py (working copy) @@ -35,6 +35,7 @@ print 'Removing \'../messaging/messagingthrift\' directory...' shutil.rmtree('../messaging/messagingthrift') + print 'Generating Python code for \'services.thrift\'...' os.system('thrift --gen py:new_style services.thrift') @@ -44,7 +45,12 @@ print 'Generatign Python code for \'messagingthrift\'...' os.system('rm -rf gen-py') os.system('thrift --gen py messagingthrift.thrift') - + + print 'Generating Python code for \'layoutlocality.thrift\'...' + os.system('thrift --gen py:new_style layoutlocality.thrift') + print 'Copying generated code to \'tashi.services\' package...' + shutil.copytree('gen-py/layoutlocality', '../services/ layoutlocality') + print 'Copying generated code to \'tashi.messaging.messagingthrift \' package...' shutil.copytree(os.path.join('gen-py', 'messagingthrift'), os.path.join('..', 'messaging', 'messagingthrift')) Index: trunk/src/tashi/thrift/layoutlocality.thrift =================================================================== --- trunk/src/tashi/thrift/layoutlocality.thrift (revision 0) +++ trunk/src/tashi/thrift/layoutlocality.thrift (revision 0) @@ -0,0 +1,26 @@ +struct BlockLocation { + list<string> hosts, // hostnames of data nodes + list<i32> ports, // ports for data nodes + list<string> names, // hostname:port of data nodes + i64 blocknum, + i64 offset, + i64 length +} + +struct Pathname { + string pathname +} + +exception FileNotFoundException { + string message +} + +service layoutservice { + + list <BlockLocation> getFileBlockLocations(1:Pathname path, 2:i64 offset, 3:i64 length) + throws (1:FileNotFoundException ouch), +} + +service localityservice { + list <list<double>> getHopCountMatrix(1:list<string> sourceHosts, 2:list<string> destHosts), +} \ No newline at end of file Index: trunk/src/tashi/agents/locality-server.py =================================================================== --- trunk/src/tashi/agents/locality-server.py (revision 0) +++ trunk/src/tashi/agents/locality-server.py (revision 0) @@ -0,0 +1,213 @@ +from socket import gethostname +import os +import threading +import time +import socket + +from tashi.services.ttypes import * + +from thrift import Thrift +from thrift.transport import TSocket +from thrift.transport import TTransport +from thrift.protocol import TBinaryProtocol +from thrift.server import TServer + +from tashi.services import clustermanagerservice +from tashi.util import getConfig +from tashi.parallel import * + +import tashi.services.layoutlocality.localityservice as localityservice + +from numpy import * +from scipy import * + +cnames = {} +def cannonicalName(hn): + try: + if cnames.has_key(hn): + return cnames[hn] + r = socket.gethostbyname_ex(hn)[0] + cnames[hn] = r + return r + except: + return hn + + +def createClient(config): + host = config.get('Client', 'clusterManagerHost') + port = config.get('Client', 'clusterManagerPort') + print host, port + timeout = float(config.get('Client', 'clusterManagerTimeout')) * 1000.0 + + socket = TSocket.TSocket(host, int(port)) + socket.setTimeout(timeout) + transport = TTransport.TBufferedTransport(socket) + protocol = TBinaryProtocol.TBinaryProtocol(transport) + client = clustermanagerservice.Client(protocol) + try: + transport.open() + except: + pass + return (client, transport) + + +def genMul(A, B, add, mult): + '''generalized matrix multiplication''' + C = zeros((shape(A)[0], shape(B)[1])) + for i in range(shape(C)[0]): + for j in range(shape(C)[1]): + C[i,j] = add(mult(A[i,:], B[:,j])) + return C + +def addHost(graph, hostVals, host): + if not graph.has_key(host): + graph[host] = [] + if not hostVals.has_key(host): + hostVals[host] = len(hostVals) + +def graphConnect(graph, h1, h2): + if not h1 in graph[h2]: + graph[h2].append(h1) + if not h2 in graph[h1]: + graph[h1].append(h2) + +def graphFromFile(fn = 'serverLayout', graph = {}, hostVals = {}): + f = open(fn) + for line in f.readlines(): + line = line.split() + if len(line) < 1: + continue + server = cannonicalName(line[0].strip()) + + addHost(graph, hostVals, server) + for peer in line[1:]: + peer = cannonicalName(peer.strip()) + addHost(graph, hostVals, peer) + graphConnect(graph, server, peer) + return graph, hostVals + +def graphFromTashi(client, transport, graph={}, hostVals={}): + print 'getting graph' + if not transport.isOpen(): + transport.open() + hosts = client.getHosts() + instances = client.getInstances() + for instance in instances: + host = [cannonicalName(h.name) for h in hosts if h.id == instance.hostId] + if len(host) <1 : + print 'cant find vm host' + continue + host = host[0] + print 'host is ', host + addHost(graph, hostVals, host) + print 'added host' + vmhost = cannonicalName(instance.name) + addHost(graph, hostVals, vmhost) + print 'added vm' + graphConnect(graph, host, vmhost) + print 'connected' + print 'returning from graphFromTashi' + return graph, hostVals + + + +def graphToArray(graph, hostVals): + a = zeros((len(hostVals), len(hostVals))) + for host in graph.keys(): + if not hostVals.has_key(host): + continue + a[hostVals[host], hostVals[host]] = 1 + for peer in graph[host]: + if not hostVals.has_key(peer): + continue + a[hostVals[host], hostVals[peer]] = 1 + a[a==0] = inf + for i in range(shape(a)[0]): + a[i,i]=0 + return a + +def shortestPaths(graphArray): + a = graphArray + for i in range(math.ceil(math.log(shape(a)[0],2))): + a = genMul(a,a,min,plus) + return a + +def plus(A, B): + return A + B + + +def getHopCountMatrix(sourceHosts, destHosts, array, hostVals): + a = zeros((len(sourceHosts), len(destHosts))) + a[a==0] = inf + for i in range(len(sourceHosts)): + sh = cannonicalName(sourceHosts[i]) + shv = None + if hostVals.has_key(sh): + shv = hostVals[sh] + else: + print 'host not found', sh + continue + for j in range(len(destHosts)): + dh = cannonicalName(destHosts[j]) + dhv = None + if hostVals.has_key(dh): + dhv = hostVals[dh] + else: + print 'dest not found', dh + continue + print sh, dh, i,j, shv, dhv, array[shv, dhv] + a[i,j] = array[shv, dhv] + return a + + +class LocalityService: + def __init__(self): + (config, configFiles) = getConfig(["Agent"]) + self.port = int(config.get('LocalityService', 'port')) + print 'Locality service on port %i' % self.port + self.processor = localityservice.Processor(self) + self.transport = TSocket.TServerSocket(self.port) + self.tfactory = TTransport.TBufferedTransportFactory() + self.pfactory = TBinaryProtocol.TBinaryProtocolFactory() + self.server = TServer.TThreadedServer(self.processor, + self.transport, + self.tfactory, + self.pfactory) + + self.hostVals =[] + self.array = array([[]]) + self.rtime = 0 + + + self.fileName = os.path.expanduser(config.get("LocalityService", "staticLayout")) + (self.client, self.transport) = createClient(config) + + self.server.serve() + + @synchronizedmethod + def refresh(self): + if time.time() - self.rtime < 10: + return + g, self.hostVals = graphFromFile(self.fileName) + try: + g, self.hostVals = graphFromTashi(self.client, self.transport, g, self.hostVals) + except e: + print e + print 'could not get instance list from cluster manager' + print 'graph to array' + a = graphToArray(g, self.hostVals) + print 'calling shortest paths ', a.shape + self.array = shortestPaths(a) + print 'computed shortest paths' + print self.array + print self.hostVals + @synchronizedmethod + def getHopCountMatrix(self, sourceHosts, destHosts): + self.refresh() + print 'getting hop count matrix for', sourceHosts, destHosts + hcm = getHopCountMatrix(sourceHosts, destHosts, self.array, self.hostVals) + print hcm + return hcm + + +ls = LocalityService() Index: trunk/etc/TashiDefaults.cfg =================================================================== --- trunk/etc/TashiDefaults.cfg (revision 764908) +++ trunk/etc/TashiDefaults.cfg (working copy) @@ -82,6 +82,11 @@ [Vfs] prefix = /var/tmp/ +[LayoutService] +host = layoutserver +port = 9884 +staticLayout = /location/of/layout/file + # Client configuration [Client] clusterManagerHost = localhost From tashi-dev-returnamber38@example.com Tue Apr 14 19:37:09 2009 Return-Path: <tashi-dev-returnamber38@example.com> Delivered-To: amber38@example.com Received: (qmail 37958 invoked from network); 14 Apr 2009 19:37:08 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (83.161.120.155) by minotaur.apache.org with SMTP; 14 Apr 2009 19:37:08 -0000 Received: (qmail 39837 invoked by uid 500); 14 Apr 2009 19:37:08 -0000 Delivered-To: amber38@example.com Received: (qmail 39811 invoked by uid 500); 14 Apr 2009 19:37:08 -0000 Mailing-List: contact amber38@example.com; run by ezmlm Precedence: bulk List-Help: <mailto:amber38@example.com> List-Unsubscribe: <mailto:amber38@example.com> List-Post: <mailto:amber38@example.com> List-Id: <tashi-dev.incubator.apache.org> Reply-To: amber38@example.com Delivered-To: mailing list amber38@example.com Received: (qmail 39801 invoked by uid 99); 14 Apr 2009 19:37:08 -0000 Received: from nike.apache.org (HELO nike.apache.org) (83.161.120.155) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 14 Apr 2009 19:37:08 +0000 X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: local policy) Received: from [83.161.120.155] (HELO smtp.andrew.cmu.edu) (83.161.120.155) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 14 Apr 2009 19:37:01 +0000 Received: from CMU-255281.WV.CC.CMU.EDU (CMU-255281.WV.CC.CMU.EDU [83.161.120.155]) (user=jcipar mech=PLAIN (0 bits)) by smtp.andrew.cmu.edu (8.14.3/8.13.8) with ESMTP id n3EJacWu027700 (version=TLSv1/SSLv3 cipher=AES128-SHA bits=128 verify=NOT) for <amber38@example.com>; Tue, 14 Apr 2009 15:36:39 -0400 Message-Id: <amber38@example.com> From: James Cipar <amber38@example.com> To: amber38@example.com In-Reply-To: <amber38@example.com> Content-Type: text/plain; charset=US-ASCII; format=flowed; delsp=yes Content-Transfer-Encoding: 7bit Mime-Version: 1.0 (Apple Message framework v930.3) Subject: Re: Locality server Date: Tue, 14 Apr 2009 15:36:38 -0400 References: <amber38@example.com> <amber38@example.com> X-Mailer: Apple Mail (2.930.3) X-PMX-Version: 83.161.120.1556731, Antispam-Engine: 83.161.120.1556912, Antispam-Data: 283.161.120.155541 X-SMTP-Spam-Clean: 8% (LEO_OBFU_SUBJ_RE 0.1, BODY_SIZE_10000_PLUS 0, TO_NO_NAME 0, __BOUNCE_CHALLENGE_SUBJ 0, __CP_MEDIA_BODY 0, __CT 0, __CTE 0, __CT_TEXT_PLAIN 0, __HAS_MSGID 0, __HAS_X_MAILER 0, __MIME_TEXT_ONLY 0, __MIME_VERSION 0, __MSGID_APPLEMAIL 0, __SANE_MSGID 0, __TO_MALFORMED_2 0) X-SMTP-Spam-Score: 8% X-Scanned-By: MIMEDefang 2.60 on 83.161.120.155 X-Virus-Checked: Checked by ClamAV on apache.org Forgot to mention: requires numpy and scipy. I'll work on getting rid of those requirements. On Apr 14, 2009, at 3:33 PM, Jim Cipar wrote: > I've been working on the Tashi locality server. It exports a > service that will give the hop count between any set of nodes that > it knows about. This can be used by, e.g., an HDFS Client that is > running in a VM, to determine which node to read data from. This > case requires modifying the HDFS client code, but it is an example > of how something like this could be useful. > > The only call exported right now is: > list <list <float>> getHopCountMatrix(list <string>sources, list > <string> destinations) > This returns the complete hop count matrix between sources and > destinations, with positive infinity for any nodes that are either > unknown, or not connected. It gathers information about static > network objects from a configuration file describing all adjacent > things (nodes, switches ...) in the network. Each line of the file > has one source, and any number of destinations. For instance, a > simple cluster with one top level switch, and two switches each with > two hosts might be configured like this: > > toplevel switch1 switch2 > switch1 toplevel host1 host2 > switch2 toplevel host3 host4 > > All physical objects on the network are configured via the > configuration file. Information about currently running Tashi VMs, > is automatically gathered from the Tashi Cluster Manager, and these > are added to the graph. > > Lastly, there is a script ( src/utils/getLocality.py ) that can be > used to contact this service. The script takes two lines of input > on stdin: a whitespace separated list of sources, and a whitespace > separated list of destinations. It then prints the distance matrix > with a row for each source, and a column for each destination. It > then waits for two more lines of input on stdin. It will continue > until it receives an EOF on stdin. > > Here's the patch: > > > > Index: trunk/src/utils/getLocality.py > =================================================================== > --- trunk/src/utils/getLocality.py (revision 0) > +++ trunk/src/utils/getLocality.py (revision 0) > @@ -0,0 +1,53 @@ > +#!/usr/bin/python > + > +import sys > +import os > +from os import system > + > +import tashi.services.layoutlocality.localityservice as > localityservice > + > +from thrift import Thrift > +from thrift.transport import TSocket > +from thrift.transport import TTransport > +from thrift.protocol import TBinaryProtocol > + > +from tashi.util import getConfig > + > +(config, configFiles) = getConfig(["Client"]) > +host = config.get('LocalityService', 'host') > +port = int(config.get('LocalityService', 'port')) > + > +socket = TSocket.TSocket(host, port) > +transport = TTransport.TBufferedTransport(socket) > +protocol = TBinaryProtocol.TBinaryProtocol(transport) > +client = localityservice.Client(protocol) > +transport.open() > + > + > +while True: > + line1 = "\n" > + line2 = "\n" > + while line1 != "": > + line1 = sys.stdin.readline() > + if line1 == "": > + sys.exit(0) > + if line1 != "\n": > + break > + line1 = line1.strip() > + while line2 != "": > + line2 = sys.stdin.readline() > + if line2 == "": > + sys.exit(0) > + if line2 != "\n": > + break > + line2 = line2.strip() > + > + sources = line1.split(" ") > + destinations = line2.split(" ") > + > + mat = client.getHopCountMatrix(sources, destinations) > + for r in mat: > + for c in r: > + print '%f\t'%c, > + print '\n', > + print '\n', > > Property changes on: trunk/src/utils/getLocality.py > ___________________________________________________________________ > Added: svn:executable > + * > > Index: trunk/src/tashi/nodemanager/vmcontrol/xenpv.py > =================================================================== > --- trunk/src/tashi/nodemanager/vmcontrol/xenpv.py (revision 764908) > +++ trunk/src/tashi/nodemanager/vmcontrol/xenpv.py (working copy) > @@ -156,9 +156,9 @@ > image, macAddr, memory, cores): > fn = os.path.join("/tmp", vmName) > cfgstr = """ > -# kernel="/boot/vmlinuz-2.6.24-17-xen" > -# ramdisk="/boot/initrd.img-2.6.24-17-xen" > -bootloader="/usr/bin/pygrub" > +kernel="/boot/vmlinuz-2.6.24-17-xen" > +ramdisk="/boot/initrd.img-2.6.24-17-xen" > +# bootloader="/usr/bin/pygrub" > disk=['tap:qcow:%s,xvda1,w'] > vif = [ 'mac=%s' ] > # vif = ['ip=83.161.120.155'] > Index: trunk/src/tashi/thrift/build.py > =================================================================== > --- trunk/src/tashi/thrift/build.py (revision 764908) > +++ trunk/src/tashi/thrift/build.py (working copy) > @@ -35,6 +35,7 @@ > print 'Removing \'../messaging/messagingthrift\' directory...' > shutil.rmtree('../messaging/messagingthrift') > > + > print 'Generating Python code for \'services.thrift\'...' > os.system('thrift --gen py:new_style services.thrift') > > @@ -44,7 +45,12 @@ > print 'Generatign Python code for \'messagingthrift\'...' > os.system('rm -rf gen-py') > os.system('thrift --gen py messagingthrift.thrift') > - > + > + print 'Generating Python code for \'layoutlocality.thrift > \'...' > + os.system('thrift --gen py:new_style layoutlocality.thrift') > + print 'Copying generated code to \'tashi.services\' > package...' > + shutil.copytree('gen-py/layoutlocality', '../services/ > layoutlocality') > + > print 'Copying generated code to \'tashi.messaging.messagingthrift > \' package...' > shutil.copytree(os.path.join('gen-py', 'messagingthrift'), > os.path.join('..', 'messaging', 'messagingthrift')) > Index: trunk/src/tashi/thrift/layoutlocality.thrift > =================================================================== > --- trunk/src/tashi/thrift/layoutlocality.thrift (revision 0) > +++ trunk/src/tashi/thrift/layoutlocality.thrift (revision 0) > @@ -0,0 +1,26 @@ > +struct BlockLocation { > + list<string> hosts, // hostnames of data nodes > + list<i32> ports, // ports for data nodes > + list<string> names, // hostname:port of data nodes > + i64 blocknum, > + i64 offset, > + i64 length > +} > + > +struct Pathname { > + string pathname > +} > + > +exception FileNotFoundException { > + string message > +} > + > +service layoutservice { > + > + list <BlockLocation> getFileBlockLocations(1:Pathname path, 2:i64 > offset, 3:i64 length) > + throws (1:FileNotFoundException ouch), > +} > + > +service localityservice { > + list <list<double>> getHopCountMatrix(1:list<string> sourceHosts, > 2:list<string> destHosts), > +} > \ No newline at end of file > Index: trunk/src/tashi/agents/locality-server.py > =================================================================== > --- trunk/src/tashi/agents/locality-server.py (revision 0) > +++ trunk/src/tashi/agents/locality-server.py (revision 0) > @@ -0,0 +1,213 @@ > +from socket import gethostname > +import os > +import threading > +import time > +import socket > + > +from tashi.services.ttypes import * > + > +from thrift import Thrift > +from thrift.transport import TSocket > +from thrift.transport import TTransport > +from thrift.protocol import TBinaryProtocol > +from thrift.server import TServer > + > +from tashi.services import clustermanagerservice > +from tashi.util import getConfig > +from tashi.parallel import * > + > +import tashi.services.layoutlocality.localityservice as > localityservice > + > +from numpy import * > +from scipy import * > + > +cnames = {} > +def cannonicalName(hn): > + try: > + if cnames.has_key(hn): > + return cnames[hn] > + r = socket.gethostbyname_ex(hn)[0] > + cnames[hn] = r > + return r > + except: > + return hn > + > + > +def createClient(config): > + host = config.get('Client', 'clusterManagerHost') > + port = config.get('Client', 'clusterManagerPort') > + print host, port > + timeout = float(config.get('Client', 'clusterManagerTimeout')) > * 1000.0 > + > + socket = TSocket.TSocket(host, int(port)) > + socket.setTimeout(timeout) > + transport = TTransport.TBufferedTransport(socket) > + protocol = TBinaryProtocol.TBinaryProtocol(transport) > + client = clustermanagerservice.Client(protocol) > + try: > + transport.open() > + except: > + pass > + return (client, transport) > + > + > +def genMul(A, B, add, mult): > + '''generalized matrix multiplication''' > + C = zeros((shape(A)[0], shape(B)[1])) > + for i in range(shape(C)[0]): > + for j in range(shape(C)[1]): > + C[i,j] = add(mult(A[i,:], B[:,j])) > + return C > + > +def addHost(graph, hostVals, host): > + if not graph.has_key(host): > + graph[host] = [] > + if not hostVals.has_key(host): > + hostVals[host] = len(hostVals) > + > +def graphConnect(graph, h1, h2): > + if not h1 in graph[h2]: > + graph[h2].append(h1) > + if not h2 in graph[h1]: > + graph[h1].append(h2) > + > +def graphFromFile(fn = 'serverLayout', graph = {}, hostVals = {}): > + f = open(fn) > + for line in f.readlines(): > + line = line.split() > + if len(line) < 1: > + continue > + server = cannonicalName(line[0].strip()) > + > + addHost(graph, hostVals, server) > + for peer in line[1:]: > + peer = cannonicalName(peer.strip()) > + addHost(graph, hostVals, peer) > + graphConnect(graph, server, peer) > + return graph, hostVals > + > +def graphFromTashi(client, transport, graph={}, hostVals={}): > + print 'getting graph' > + if not transport.isOpen(): > + transport.open() > + hosts = client.getHosts() > + instances = client.getInstances() > + for instance in instances: > + host = [cannonicalName(h.name) for h in hosts if h.id == > instance.hostId] > + if len(host) <1 : > + print 'cant find vm host' > + continue > + host = host[0] > + print 'host is ', host > + addHost(graph, hostVals, host) > + print 'added host' > + vmhost = cannonicalName(instance.name) > + addHost(graph, hostVals, vmhost) > + print 'added vm' > + graphConnect(graph, host, vmhost) > + print 'connected' > + print 'returning from graphFromTashi' > + return graph, hostVals > + > + > + > +def graphToArray(graph, hostVals): > + a = zeros((len(hostVals), len(hostVals))) > + for host in graph.keys(): > + if not hostVals.has_key(host): > + continue > + a[hostVals[host], hostVals[host]] = 1 > + for peer in graph[host]: > + if not hostVals.has_key(peer): > + continue > + a[hostVals[host], hostVals[peer]] = 1 > + a[a==0] = inf > + for i in range(shape(a)[0]): > + a[i,i]=0 > + return a > + > +def shortestPaths(graphArray): > + a = graphArray > + for i in range(math.ceil(math.log(shape(a)[0],2))): > + a = genMul(a,a,min,plus) > + return a > + > +def plus(A, B): > + return A + B > + > + > +def getHopCountMatrix(sourceHosts, destHosts, array, hostVals): > + a = zeros((len(sourceHosts), len(destHosts))) > + a[a==0] = inf > + for i in range(len(sourceHosts)): > + sh = cannonicalName(sourceHosts[i]) > + shv = None > + if hostVals.has_key(sh): > + shv = hostVals[sh] > + else: > + print 'host not found', sh > + continue > + for j in range(len(destHosts)): > + dh = cannonicalName(destHosts[j]) > + dhv = None > + if hostVals.has_key(dh): > + dhv = hostVals[dh] > + else: > + print 'dest not found', dh > + continue > + print sh, dh, i,j, shv, dhv, array[shv, dhv] > + a[i,j] = array[shv, dhv] > + return a > + > + > +class LocalityService: > + def __init__(self): > + (config, configFiles) = getConfig(["Agent"]) > + self.port = int(config.get('LocalityService', 'port')) > + print 'Locality service on port %i' % self.port > + self.processor = localityservice.Processor(self) > + self.transport = TSocket.TServerSocket(self.port) > + self.tfactory = TTransport.TBufferedTransportFactory() > + self.pfactory = TBinaryProtocol.TBinaryProtocolFactory() > + self.server = TServer.TThreadedServer(self.processor, > + self.transport, > + self.tfactory, > + self.pfactory) > + > + self.hostVals =[] > + self.array = array([[]]) > + self.rtime = 0 > + > + > + self.fileName = > os.path.expanduser(config.get("LocalityService", "staticLayout")) > + (self.client, self.transport) = createClient(config) > + > + self.server.serve() > + > + @synchronizedmethod > + def refresh(self): > + if time.time() - self.rtime < 10: > + return > + g, self.hostVals = graphFromFile(self.fileName) > + try: > + g, self.hostVals = graphFromTashi(self.client, > self.transport, g, self.hostVals) > + except e: > + print e > + print 'could not get instance list from cluster manager' > + print 'graph to array' > + a = graphToArray(g, self.hostVals) > + print 'calling shortest paths ', a.shape > + self.array = shortestPaths(a) > + print 'computed shortest paths' > + print self.array > + print self.hostVals > + @synchronizedmethod > + def getHopCountMatrix(self, sourceHosts, destHosts): > + self.refresh() > + print 'getting hop count matrix for', sourceHosts, destHosts > + hcm = getHopCountMatrix(sourceHosts, destHosts, > self.array, self.hostVals) > + print hcm > + return hcm > + > + > +ls = LocalityService() > Index: trunk/etc/TashiDefaults.cfg > =================================================================== > --- trunk/etc/TashiDefaults.cfg (revision 764908) > +++ trunk/etc/TashiDefaults.cfg (working copy) > @@ -82,6 +82,11 @@ > [Vfs] > prefix = /var/tmp/ > > +[LayoutService] > +host = layoutserver > +port = 9884 > +staticLayout = /location/of/layout/file > + > # Client configuration > [Client] > clusterManagerHost = localhost > From tashi-dev-returnamber38@example.com Fri Apr 17 18:00:31 2009 Return-Path: <tashi-dev-returnamber38@example.com> Delivered-To: amber38@example.com Received: (qmail 72215 invoked from network); 17 Apr 2009 18:00:30 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (83.161.120.155) by minotaur.apache.org with SMTP; 17 Apr 2009 18:00:30 -0000 Received: (qmail 42590 invoked by uid 500); 17 Apr 2009 18:00:29 -0000 Delivered-To: amber38@example.com Received: (qmail 42559 invoked by uid 500); 17 Apr 2009 18:00:29 -0000 Mailing-List: contact amber38@example.com; run by ezmlm Precedence: bulk List-Help: <mailto:amber38@example.com> List-Unsubscribe: <mailto:amber38@example.com> List-Post: <mailto:amber38@example.com> List-Id: <tashi-dev.incubator.apache.org> Reply-To: amber38@example.com Delivered-To: mailing list amber38@example.com Received: (qmail 42549 invoked by uid 99); 17 Apr 2009 18:00:29 -0000 Received: from athena.apache.org (HELO athena.apache.org) (83.161.120.155) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 17 Apr 2009 18:00:29 +0000 X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (athena.apache.org: local policy) Received: from [83.161.120.155] (HELO smtp.andrew.cmu.edu) (83.161.120.155) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 17 Apr 2009 18:00:24 +0000 Received: from CMU-255281.WV.CC.CMU.EDU (CMU-255281.WV.CC.CMU.EDU [83.161.120.155]) (user=jcipar mech=PLAIN (0 bits)) by smtp.andrew.cmu.edu (8.14.3/8.13.8) with ESMTP id n3HI027E001509 (version=TLSv1/SSLv3 cipher=AES128-SHA bits=128 verify=NOT) for <amber38@example.com>; Fri, 17 Apr 2009 14:00:03 -0400 Message-Id: <amber38@example.com> From: James Cipar <amber38@example.com> To: amber38@example.com Content-Type: text/plain; charset=US-ASCII; format=flowed; delsp=yes Content-Transfer-Encoding: 7bit Mime-Version: 1.0 (Apple Message framework v930.3) Subject: getHostInfo in vmcontrol Date: Fri, 17 Apr 2009 14:00:02 -0400 X-Mailer: Apple Mail (2.930.3) X-PMX-Version: 83.161.120.1556731, Antispam-Engine: 83.161.120.1556912, Antispam-Data: 283.161.120.155929 X-SMTP-Spam-Clean: 8% (BODY_SIZE_10000_PLUS 0, TO_NO_NAME 0, __CP_MEDIA_BODY 0, __CP_NAME_BODY 0, __CP_URI_IN_BODY 0, __CT 0, __CTE 0, __CT_TEXT_PLAIN 0, __HAS_MSGID 0, __HAS_X_MAILER 0, __LINES_OF_YELLING 0, __MIME_TEXT_ONLY 0, __MIME_VERSION 0, __MSGID_APPLEMAIL 0, __SANE_MSGID 0, __STOCK_PHRASE_7 0, __TO_MALFORMED_2 0) X-SMTP-Spam-Score: 8% X-Scanned-By: MIMEDefang 2.60 on 83.161.120.155 X-Virus-Checked: Checked by ClamAV on apache.org The implementation of getHostInfo makes some assumptions that are not true in Xen. Specifically, it uses the resources that the host OS (dom0) reports as the actual resources available to guests. This is usually not the case. The memory size reported by /proc/meminfo is the amount dedicated to dom0, i.e. TotalMemory- Sum(GuestMemory). Also, the number of CPUs reported by "os.sysconf('SC_NPROCESSORS_ONLN')" is the number that dom0 is configured to use, which may be less than the total number available. The proper way to get info about the host in Xen is "xm info". Perhaps this function should be moved to the VmControl class, so that it can be overridden by implementations that get the info in different ways. Patch is below. It also includes some changes to the xen code. Xen now supports different methods of booting via hints. diff -r 3f66cc24ef92 trunk/etc/TashiDefaults.cfg --- a/trunk/etc/TashiDefaults.cfg Fri Apr 17 10:53:55 2009 -0400 +++ b/trunk/etc/TashiDefaults.cfg Fri Apr 17 13:58:55 2009 -0400 @@ -78,6 +78,9 @@ useMigrateArgument = False [XenPV] vmNamePrefix = tashi transientdir = /tmp +defaultVmType = kernel +defaultKernel = /boot/vmlinuz-xen +defaultRamdisk = /boot/initrd-xen [Vfs] prefix = /var/tmp/ diff -r 3f66cc24ef92 trunk/src/tashi/nodemanager/nodemanagerservice.py --- a/trunk/src/tashi/nodemanager/nodemanagerservice.py Fri Apr 17 10:53:55 2009 -0400 +++ b/trunk/src/tashi/nodemanager/nodemanagerservice.py Fri Apr 17 13:58:55 2009 -0400 @@ -98,29 +98,7 @@ class NodeManagerService(object): else: success() return True - - def getHostInfo(self): - host = Host() - host.id = self.id - host.name = socket.gethostname() - memoryStr = os.popen2("head -n 1 /proc/meminfo | awk '{print $2 \" \" $3}'")[1].read().strip() - if (memoryStr[-2:] == "kB"): - host.memory = int(memoryStr[:-2])/1024 - elif (memoryStr[-2:] == "mB"): - host.memory = int(memoryStr[:-2]) - elif (memoryStr[-2:] == "gB"): - host.memory = int(memoryStr[:-2])*1024 - elif (memoryStr[-2:] == " B"): - host.memory = int(memoryStr[:-2])/(1024*1024) - else: - self.log.warning('Unable to determine amount of physical memory - reporting 0') - host.memory = 0 - host.cores = os.sysconf("SC_NPROCESSORS_ONLN") - host.up = True - host.decayed = False - host.version = version - return host - + def backupVmInfoAndFlushNotifyCM(self): cm = ConnectionManager(clustermanagerservice.Client, self.cmPort) [self.cmHost] while True: @@ -158,7 +136,7 @@ class NodeManagerService(object): while True: start = time.time() try: - host = self.getHostInfo() + host = self.vmm.getHostInfo(self) instances = self.instances.values() self.id = cm.registerNodeManager(host, instances) except Exception, e: diff -r 3f66cc24ef92 trunk/src/tashi/nodemanager/vmcontrol/qemu.py --- a/trunk/src/tashi/nodemanager/vmcontrol/qemu.py Fri Apr 17 10:53:55 2009 -0400 +++ b/trunk/src/tashi/nodemanager/vmcontrol/qemu.py Fri Apr 17 13:58:55 2009 -0400 @@ -29,7 +29,7 @@ import time from tashi.services.ttypes import * from tashi.util import broken, logged, scrubString, boolean -from vmcontrolinterface import VmControlInterface +from vmcontrolbase import VmControlBase log = logging.getLogger(__file__) @@ -79,7 +79,7 @@ def controlConsole(child, port): #print "Thread exiting" pass -class Qemu(VmControlInterface): +class Qemu(VmControlBase): """This class implements the VmControlInterface for Qemu/KVM""" def __init__(self, config, dfs, nm): diff -r 3f66cc24ef92 trunk/src/tashi/nodemanager/vmcontrol/ vmcontrolbase.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/tashi/nodemanager/vmcontrol/vmcontrolbase.py Fri Apr 17 13:58:55 2009 -0400 @@ -0,0 +1,49 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + +import socket +from tashi.services.ttypes import Host +from vmcontrolinterface import VmControlInterface + +class VmControlBase(VmControlInterface): + '''Base class for VmControl types. Implements default versions of + common functions.''' + + def getHostInfo(self, nodemanager): + print 'called gethostinfo' + host = Host() + host.id = nodemanager.id + host.name = socket.gethostname() + memoryStr = os.popen2("head -n 1 /proc/meminfo | awk '{print $2 \" \" $3}'")[1].read().strip() + if (memoryStr[-2:] == "kB"): + host.memory = int(memoryStr[:-2])/1024 + elif (memoryStr[-2:] == "mB"): + host.memory = int(memoryStr[:-2]) + elif (memoryStr[-2:] == "gB"): + host.memory = int(memoryStr[:-2])*1024 + elif (memoryStr[-2:] == " B"): + host.memory = int(memoryStr[:-2])/(1024*1024) + else: + self.log.warning('Unable to determine amount of physical memory - reporting 0') + host.memory = 0 + host.cores = os.sysconf("SC_NPROCESSORS_ONLN") + host.up = True + host.decayed = False + host.version = version + return host + diff -r 3f66cc24ef92 trunk/src/tashi/nodemanager/vmcontrol/ vmcontrolinterface.py --- a/trunk/src/tashi/nodemanager/vmcontrol/vmcontrolinterface.py Fri Apr 17 10:53:55 2009 -0400 +++ b/trunk/src/tashi/nodemanager/vmcontrol/vmcontrolinterface.py Fri Apr 17 13:58:55 2009 -0400 @@ -79,3 +79,6 @@ class VmControlInterface(object): def listVms(self): """Returns a list of vmIds to the caller""" raise NotImplementedError + def getHostInfo(self): + """Returns a Host object for the current host""" + raise NotImplementedError diff -r 3f66cc24ef92 trunk/src/tashi/nodemanager/vmcontrol/xenpv.py --- a/trunk/src/tashi/nodemanager/vmcontrol/xenpv.py Fri Apr 17 10:53:55 2009 -0400 +++ b/trunk/src/tashi/nodemanager/vmcontrol/xenpv.py Fri Apr 17 13:58:55 2009 -0400 @@ -22,11 +22,12 @@ import time import time import threading import logging +import socket -from vmcontrolinterface import VmControlInterface +from vmcontrolbase import VmControlBase from tashi.services.ttypes import Errors, InstanceState, TashiException from tashi.services.ttypes import Instance, Host -from tashi import boolean, convertExceptions, ConnectionManager +from tashi import boolean, convertExceptions, ConnectionManager, version from tashi.util import isolatedRPC import tashi.parallel @@ -90,7 +91,6 @@ def listVms(prefix='tashi'): instance.memory = int(vminfo['memory']) instance.cores = int(vminfo['cores']) instance.disks = [] - r[instance.vmId] = instance return r @@ -98,17 +98,16 @@ def listVms(prefix='tashi'): -class XenPV(VmControlInterface, threading.Thread): +class XenPV(VmControlBase, threading.Thread): def __init__(self, config, dfs, cm): threading.Thread.__init__(self) - if self.__class__ is VmControlInterface: - raise NotImplementedError self.config = config self.dfs = dfs self.cm = cm - self.vmNamePrefix = self.config.get("XenPV", "vmNamePrefix") + self.vmNamePrefix = self.config.get('XenPV', 'vmNamePrefix') self.transientDir = self.config.get('XenPV', 'transientDir') + self.defaultVmType = self.config.get('XenPV', 'defaultVmType') self.newvms = listVms(self.vmNamePrefix) self.hostId = -1 @@ -142,7 +141,6 @@ class XenPV(VmControlInterface, threadin if not self.newvms.has_key(vmId): print 'WARNING: found vm that should be managed, but is not' # FIXME: log that - def run(self): while(True): @@ -153,24 +151,61 @@ class XenPV(VmControlInterface, threadin # a lot easier ######################################## def createXenConfig(self, vmName, - image, macAddr, memory, cores): + image, macAddr, memory, cores, hints): fn = os.path.join("/tmp", vmName) + vmType = hints.get('vmtype', self.defaultVmType) + print 'starting vm with type: ', vmType + bootstr = '' + if vmType == 'pvgrub': + # FIXME: untested, requires Xen 3.3 + bootstr = ''' +kernel = '/usr/lib/xen/boot/pv-grub-x86_64.gz' +extra = '(hd0,0)/grub/menu.lst' +''' + elif vmType == 'pygrub': + bootstr = ''' +bootloader="/usr/bin/pygrub" +''' + elif vmType == 'kernel': + kernel = hints.get('kernel', None) + ramdisk = hints.get('ramdisk', None) + if kernel == None: + try: + kernel = self.config.get('XenPV', 'defaultKernel') + except: + raise Exception, "vmtype=kernel requires kernel= argument" + bootstr = "kernel=\"%s\"\n"%kernel + if ramdisk == None: + try: + ramdisk = self.config.get('XenPV', 'defaultRamdisk') + except: + ramdisk = None + if ramdisk != None: + bootstr = bootstr + "ramdisk = \"%s \"\n"%ramdisk + elif vmType == 'hvm': + # FIXME: untested, I don't have any hvm domains set up + bootstr = ''' +import os, re +arch = os.uname()[4] +if re.search('63', arch): + arch_libdir = 'lib64' +else: + arch_libdir = 'lib' +kernel = '/usr/lib/xen/boot/hvmlocader' +builder = 'hvm' +''' + else: + raise Exception, "Unknown vmType in hints: %s"%vmType cfgstr = """ -# kernel="/boot/vmlinuz-2.6.24-17-xen" -# ramdisk="/boot/initrd.img-2.6.24-17-xen" -bootloader="/usr/bin/pygrub" disk=['tap:qcow:%s,xvda1,w'] vif = [ 'mac=%s' ] -# vif = ['ip=83.161.120.155'] -# vif = [''] memory=%i -#cpus is a list of cpus for pinning, this is not what we want -#cpus=%i +vcpus=%i root="/dev/xvda1" extra='xencons=tty' """%(image, macAddr, memory, cores) f = open(fn, "w") - f.write(cfgstr) + f.write(bootstr+cfgstr) f.close() return fn def deleteXenConfig(self, vmName): @@ -213,7 +248,8 @@ extra='xencons=tty' instance.disks[0].local, instance.nics[0].mac, instance.memory, - instance.cores) + instance.cores, + instance.hints) cmd = "xm create %s"%fn r = os.system(cmd) # self.deleteXenConfig(name) @@ -349,8 +385,10 @@ extra='xencons=tty' @synchronizedmethod - def getHostInfo(self): + def getHostInfo(self, nodemanager): host = Host() + host.id = nodemanager.id + host.name = socket.gethostname() memp = subprocess.Popen("xm info | awk '/^total_memory/ { print $3 }' ", shell = True, stdout = subprocess.PIPE) @@ -361,6 +399,9 @@ extra='xencons=tty' stdout = subprocess.PIPE) cores = corep.stdout.readline() host.cores = int(cores) + host.up = True + host.decayed = False + host.version = version return host From tashi-dev-returnamber38@example.com Tue Apr 21 18:48:41 2009 Return-Path: <tashi-dev-returnamber38@example.com> Delivered-To: amber38@example.com Received: (qmail 60277 invoked from network); 21 Apr 2009 18:48:41 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (83.161.120.155) by minotaur.apache.org with SMTP; 21 Apr 2009 18:48:41 -0000 Received: (qmail 93963 invoked by uid 500); 21 Apr 2009 18:48:41 -0000 Delivered-To: amber38@example.com Received: (qmail 93932 invoked by uid 500); 21 Apr 2009 18:48:41 -0000 Mailing-List: contact amber38@example.com; run by ezmlm Precedence: bulk List-Help: <mailto:amber38@example.com> List-Unsubscribe: <mailto:amber38@example.com> List-Post: <mailto:amber38@example.com> List-Id: <tashi-dev.incubator.apache.org> Reply-To: amber38@example.com Delivered-To: mailing list amber38@example.com Received: (qmail 93922 invoked by uid 99); 21 Apr 2009 18:48:41 -0000 Received: from nike.apache.org (HELO nike.apache.org) (83.161.120.155) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 21 Apr 2009 18:48:41 +0000 X-ASF-Spam-Status: No, hits=-4.0 required=10.0 tests=RCVD_IN_DNSWL_MED,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (nike.apache.org: local policy) Received: from [83.161.120.155] (HELO mga11.intel.com) (83.161.120.155) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 21 Apr 2009 18:48:35 +0000 Received: from fmsmga001.fm.intel.com ([83.161.120.155]) by fmsmga102.fm.intel.com with ESMTP; 21 Apr 2009 11:43:33 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.40,225,1239001200"; d="scan'208";a="683581645" Received: from rrsmsx602.amr.corp.intel.com ([83.161.120.155]) by fmsmga001.fm.intel.com with ESMTP; 21 Apr 2009 11:51:49 -0700 Received: from rrsmsx002.amr.corp.intel.com (83.161.120.155) by rrsmsx602.amr.corp.intel.com (83.161.120.155) with Microsoft SMTP Server (TLS) id 8.1.340.0; Tue, 21 Apr 2009 12:48:10 -0600 Received: from rrsmsx503.amr.corp.intel.com ([83.161.120.155]) by rrsmsx002.amr.corp.intel.com ([83.161.120.155]) with mapi; Tue, 21 Apr 2009 12:48:11 -0600 From: "Ryan, Michael P" <amber38@example.com> To: "amber38@example.com" <amber38@example.com> Date: Tue, 21 Apr 2009 12:48:08 -0600 Subject: RE: Locality server Thread-Topic: Locality server Thread-Index: Acm9OGeUCJYDp24fT+SOHCIDF0PVcwFV5sCg Message-ID: <amber38@example.com> References: <amber38@example.com> <amber38@example.com> <amber38@example.com> In-Reply-To: <amber38@example.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: acceptlanguage: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-Virus-Checked: Checked by ClamAV on apache.org Changes to Jim's patch: * removed seemingly unrelated change to xenpv.py * indentation fix (thanks "make tidy") * tweaked changes to build.py (maintain similar ordering to previou= s statements) * made src/tashi/agents/locality-server.py executable * used util.createClient instead of duplicating code in locality-se= rver.py * added a main() method to locality-server.py (common for executabl= e files) * changed the section called "LayoutService" to "LocalityService" (= it didn't run without doing this) Is there anything I wrongly changed? Index: src/utils/getLocality.py =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- src/utils/getLocality.py (revision 0) +++ src/utils/getLocality.py (revision 0) @@ -0,0 +1,52 @@ +#!/usr/bin/python + +import sys +import os +from os import system + +import tashi.services.layoutlocality.localityservice as localityservice + +from thrift import Thrift +from thrift.transport import TSocket +from thrift.transport import TTransport +from thrift.protocol import TBinaryProtocol + +from tashi.util import getConfig + +(config, configFiles) =3D getConfig(["Client"]) +host =3D config.get('LocalityService', 'host') +port =3D int(config.get('LocalityService', 'port')) + +socket =3D TSocket.TSocket(host, port) +transport =3D TTransport.TBufferedTransport(socket) +protocol =3D TBinaryProtocol.TBinaryProtocol(transport) +client =3D localityservice.Client(protocol) +transport.open() + +while True: + line1 =3D "\n" + line2 =3D "\n" + while line1 !=3D "": + line1 =3D sys.stdin.readline() + if line1 =3D=3D "": + sys.exit(0) + if line1 !=3D "\n": + break + line1 =3D line1.strip() + while line2 !=3D "": + line2 =3D sys.stdin.readline() + if line2 =3D=3D "": + sys.exit(0) + if line2 !=3D "\n": + break + line2 =3D line2.strip() + + sources =3D line1.split(" ") + destinations =3D line2.split(" ") + + mat =3D client.getHopCountMatrix(sources, destinations) + for r in mat: + for c in r: + print '%f\t'%c, + print '\n', + print '\n', Property changes on: src/utils/getLocality.py ___________________________________________________________________ Added: svn:executable + * Index: src/tashi/thrift/build.py =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- src/tashi/thrift/build.py (revision 767156) +++ src/tashi/thrift/build.py (working copy) @@ -48,3 +48,9 @@ print 'Copying generated code to \'tashi.messaging.messagingthrift\= ' package...' shutil.copytree(os.path.join('gen-py', 'messagingthrift'), os.path.join('..', 'messaging', 'messagingthrift')) + + print 'Generating Python code for \'layoutlocality.thrift\'...' + os.system('thrift --gen py:new_style layoutlocality.thrift') + + print 'Copying generated code to \'tashi.services\' package...' + shutil.copytree('gen-py/layoutlocality', '../services/layoutlocalit= y') Index: src/tashi/thrift/layoutlocality.thrift =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- src/tashi/thrift/layoutlocality.thrift (revision 0) +++ src/tashi/thrift/layoutlocality.thrift (revision 0) @@ -0,0 +1,25 @@ +struct BlockLocation { + list<string> hosts, // hostnames of data nodes + list<i32> ports, // ports for data nodes + list<string> names, // hostname:port of data nodes + i64 blocknum, + i64 offset, + i64 length +} + +struct Pathname { + string pathname +} + +exception FileNotFoundException { + string message +} + +service layoutservice { + list <BlockLocation> getFileBlockLocations(1:Pathname path, 2:i64 o= ffset, 3:i64 length) + throws (1:FileNotFoundException ouch), +} + +service localityservice { + list <list<double>> getHopCountMatrix(1:list<string> sourceHosts, 2= :list<string> destHosts), +} Index: src/tashi/agents/locality-server.py =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- src/tashi/agents/locality-server.py (revision 0) +++ src/tashi/agents/locality-server.py (revision 0) @@ -0,0 +1,200 @@ +#! /usr/bin/env python + +from socket import gethostname +import os +import threading +import time +import socket + +from tashi.services.ttypes import * + +from thrift import Thrift +from thrift.transport import TSocket +from thrift.transport import TTransport +from thrift.protocol import TBinaryProtocol +from thrift.server import TServer + +from tashi.services import clustermanagerservice +from tashi.util import getConfig, createClient +from tashi.parallel import * + +import tashi.services.layoutlocality.localityservice as localityservice + +from numpy import * +from scipy import * + +cnames =3D {} +def cannonicalName(hn): + try: + if cnames.has_key(hn): + return cnames[hn] + r =3D socket.gethostbyname_ex(hn)[0] + cnames[hn] =3D r + return r + except: + return hn + +def genMul(A, B, add, mult): + '''generalized matrix multiplication''' + C =3D zeros((shape(A)[0], shape(B)[1])) + for i in range(shape(C)[0]): + for j in range(shape(C)[1]): + C[i,j] =3D add(mult(A[i,:], B[:,j])) + return C + +def addHost(graph, hostVals, host): + if not graph.has_key(host): + graph[host] =3D [] + if not hostVals.has_key(host): + hostVals[host] =3D len(hostVals) + +def graphConnect(graph, h1, h2): + if not h1 in graph[h2]: + graph[h2].append(h1) + if not h2 in graph[h1]: + graph[h1].append(h2) + +def graphFromFile(fn =3D 'serverLayout', graph =3D {}, hostVals =3D {}): + f =3D open(fn) + for line in f.readlines(): + line =3D line.split() + if len(line) < 1: + continue + server =3D cannonicalName(line[0].strip()) + + addHost(graph, hostVals, server) + for peer in line[1:]: + peer =3D cannonicalName(peer.strip()) + addHost(graph, hostVals, peer) + graphConnect(graph, server, peer) + return graph, hostVals + +def graphFromTashi(client, transport, graph=3D{}, hostVals=3D{}): + print 'getting graph' + if not transport.isOpen(): + transport.open() + hosts =3D client.getHosts() + instances =3D client.getInstances() + for instance in instances: + host =3D [cannonicalName(h.name) for h in hosts if h.id =3D= =3D instance.hostId] + if len(host) <1 : + print 'cant find vm host' + continue + host =3D host[0] + print 'host is ', host + addHost(graph, hostVals, host) + print 'added host' + vmhost =3D cannonicalName(instance.name) + addHost(graph, hostVals, vmhost) + print 'added vm' + graphConnect(graph, host, vmhost) + print 'connected' + print 'returning from graphFromTashi' + return graph, hostVals + + + +def graphToArray(graph, hostVals): + a =3D zeros((len(hostVals), len(hostVals))) + for host in graph.keys(): + if not hostVals.has_key(host): + continue + a[hostVals[host], hostVals[host]] =3D 1 + for peer in graph[host]: + if not hostVals.has_key(peer): + continue + a[hostVals[host], hostVals[peer]] =3D 1 + a[a=3D=3D0] =3D inf + for i in range(shape(a)[0]): + a[i,i]=3D0 + return a + +def shortestPaths(graphArray): + a =3D graphArray + for i in range(math.ceil(math.log(shape(a)[0],2))): + a =3D genMul(a,a,min,plus) + return a + +def plus(A, B): + return A + B + + +def getHopCountMatrix(sourceHosts, destHosts, array, hostVals): + a =3D zeros((len(sourceHosts), len(destHosts))) + a[a=3D=3D0] =3D inf + for i in range(len(sourceHosts)): + sh =3D cannonicalName(sourceHosts[i]) + shv =3D None + if hostVals.has_key(sh): + shv =3D hostVals[sh] + else: + print 'host not found', sh + continue + for j in range(len(destHosts)): + dh =3D cannonicalName(destHosts[j]) + dhv =3D None + if hostVals.has_key(dh): + dhv =3D hostVals[dh] + else: + print 'dest not found', dh + continue + print sh, dh, i,j, shv, dhv, array[shv, dhv] + a[i,j] =3D array[shv, dhv] + return a + + +class LocalityService: + def __init__(self): + (config, configFiles) =3D getConfig(["Agent"]) + self.port =3D int(config.get('LocalityService', 'port')) + print 'Locality service on port %i' % self.port + self.processor =3D localityservice.Processor(self) + self.transport =3D TSocket.TServerSocket(self.port) + self.tfactory =3D TTransport.TBufferedTransportFactory() + self.pfactory =3D TBinaryProtocol.TBinaryProtocolFactory() + self.server =3D TServer.TThreadedServer(self.processor, + = self.transport, + = self.tfactory, + = self.pfactory) + + self.hostVals =3D[] + self.array =3D array([[]]) + self.rtime =3D 0 + + + self.fileName =3D os.path.expanduser(config.get("LocalitySe= rvice", "staticLayout")) + (self.client, self.transport) =3D createClient(config) + + self.server.serve() + + @synchronizedmethod + def refresh(self): + if time.time() - self.rtime < 10: + return + g, self.hostVals =3D graphFromFile(self.fileName) + try: + g, self.hostVals =3D graphFromTashi(self.client, se= lf.transport, g, self.hostVals) + except e: + print e + print 'could not get instance list from cluster man= ager' + print 'graph to array' + a =3D graphToArray(g, self.hostVals) + print 'calling shortest paths ', a.shape + self.array =3D shortestPaths(a) + print 'computed shortest paths' + print self.array + print self.hostVals + @synchronizedmethod + def getHopCountMatrix(self, sourceHosts, destHosts): + self.refresh() + print 'getting hop count matrix for', sourceHosts, destHost= s + hcm =3D getHopCountMatrix(sourceHosts, destHosts, self.arr= ay, self.hostVals) + print hcm + return hcm + + +def main(): + ls =3D LocalityService() + +if __name__ =3D=3D "__main__": + main() Property changes on: src/tashi/agents/locality-server.py ___________________________________________________________________ Added: svn:executable + * Index: etc/TashiDefaults.cfg =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- etc/TashiDefaults.cfg (revision 767156) +++ etc/TashiDefaults.cfg (working copy) @@ -82,6 +82,11 @@ [Vfs] prefix =3D /var/tmp/ +[LocalityService] +host =3D localityserver +port =3D 9884 +staticLayout =3D /location/of/layout/file + # Client configuration [Client] clusterManagerHost =3D localhost -----Original Message----- From: James Cipar [mailto:amber38@example.com] Sent: Tuesday, April 14, 2009 3:37 PM To: amber38@example.com Subject: Re: Locality server Forgot to mention: requires numpy and scipy. I'll work on getting rid of those requirements. On Apr 14, 2009, at 3:33 PM, Jim Cipar wrote: > I've been working on the Tashi locality server. It exports a > service that will give the hop count between any set of nodes that > it knows about. This can be used
{'source': 'Apache Software Foundation Public Mail Archives'}