# 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 logging
import subprocess
import time
import os
from tashi.rpycservices.rpyctypes import User, LocalImages, Instance, Host
from tashi.clustermanager.data import DataInterface
from tashi.util import instantiateImplementation, humanReadable

class GetentOverride(DataInterface):
	def __init__(self, config):
		DataInterface.__init__(self, config)
		self.log = logging.getLogger(__name__)
		self.baseDataObject = instantiateImplementation(config.get("GetentOverride", "baseData"), config)
		self.dfs = instantiateImplementation(config.get("ClusterManager", "dfs"), config)
		self.useLocal = config.get("GetentOverride", "getentFromLocalFile")
		self.localFileName = config.get("GetentOverride", "getentLocalFile")

		self.users = {}
		self.lastUserUpdate = 0.0
		self.fetchThreshold = float(config.get("GetentOverride", "fetchThreshold"))
	
	def registerInstance(self, instance):
		if type(instance) is not Instance:
			self.log.exception("Argument is not of type Instance, but of type %s" % (type(instance)))
			raise TypeError

		return self.baseDataObject.registerInstance(instance)
	
	def acquireInstance(self, instanceId):
		return self.baseDataObject.acquireInstance(instanceId)
	
	def releaseInstance(self, instance):
		if type(instance) is not Instance:
			self.log.exception("Argument is not of type Instance, but of type %s" % (type(instance)))
			raise TypeError

		return self.baseDataObject.releaseInstance(instance)
	
	def removeInstance(self, instance):
		if type(instance) is not Instance:
			self.log.exception("Argument is not of type Instance, but of type %s" % (type(instance)))
			raise TypeError

		return self.baseDataObject.removeInstance(instance)
	
	def acquireHost(self, hostId):
		if type(hostId) is not int:
			self.log.exception("Argument is not of type int, but of type %s" % (type(hostId)))
			raise TypeError

		return self.baseDataObject.acquireHost(hostId)
	
	def releaseHost(self, host):
		if type(host) is not Host:
			self.log.exception("Argument is not of type Host, but of type %s" % (type(host)))
			raise TypeError

		return self.baseDataObject.releaseHost(host)
	
	def getHosts(self):
		return self.baseDataObject.getHosts()
	
	def getHost(self, _id):
		return self.baseDataObject.getHost(_id)
	
	def getInstances(self):
		return self.baseDataObject.getInstances()
	
	def getInstance(self, _id):
		return self.baseDataObject.getInstance(_id)
	
	def getNetworks(self):
		return self.baseDataObject.getNetworks()
	
	def getNetwork(self, _id):
		return self.baseDataObject.getNetwork(_id)

	def getImages(self):
		count = 0
		myList = []
		for i in self.dfs.list("images"):
			myFile = self.dfs.getLocalHandle("images/" + i)
			if os.path.isfile(myFile):
				image = LocalImages(d={'id':count, 'imageName':i, 'imageSize':humanReadable(self.dfs.stat(myFile)[6])})
				myList.append(image)
				count += 1
		return myList
	
	def fetchFromGetent(self):
		now = time.time()
		if (now - self.lastUserUpdate > self.fetchThreshold):
			myUsers = {}
            #  Use local getent file instead of querying the administrative db
			if self.useLocal:
				if os.path.exists(self.localFileName):
					cmd = "cat %s" % self.localFileName
					p = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
				else:
					self.log.warning("getent cache file not found (%s)" % (self.localFileName))
					p = subprocess.Popen("getent passwd".split(), stdout=subprocess.PIPE)
            #  Query administrative database
			else:
				p = subprocess.Popen("getent passwd".split(), stdout=subprocess.PIPE)

			try:
				for l in p.stdout.xreadlines():
					ws = l.strip().split(":")
					_id = int(ws[2])
					name = ws[0]
					user = User()
					user.id = _id
					user.name = name
					myUsers[_id] = user
				self.users = myUsers
				self.lastUserUpdate = now
			finally:	
				p.wait()
	
	def getUsers(self):
		self.fetchFromGetent()
		return self.users
	
	def getUser(self, _id):
		self.fetchFromGetent()
		return self.users[_id]
		
	def registerHost(self, hostname, memory, cores, version):
		return self.baseDataObject.registerHost(hostname, memory, cores, version)
	
	def unregisterHost(self, hostId):
		return self.baseDataObject.unregisterHost(hostId)

