# $SnapHashLicense:
#
# SnapLogic - Open source data services
#
# Copyright (C) 2008 - 2009, SnapLogic, Inc. All rights reserved.
#
# See http://www.snaplogic.org for more information about
# the SnapLogic project.
#
# This program is free software, distributed under the terms of
# the GNU General Public License Version 2. See the LEGAL file
# at the top of the source tree.
#
# "SnapLogic" is a trademark of SnapLogic, Inc.
#
#
# $
# $Id: cc_list.py 8047 2009-06-29 17:46:33Z dhiraj $
from __future__ import with_statement
import time
import threading
import urlparse
from snaplogic.common.config import snap_config
from snaplogic.common import snap_http_lib,snap_log
from snaplogic.snapi_base import keys
from snaplogic.common.snap_exceptions import *
from snaplogic import server
from snaplogic.server import RhResponse
_lock = threading.RLock()
_has_been_initialized = False
cc_map = {}
uri_to_cc = {}
cc_uri_sorted = []
def initialize():
"""
Initialize the list of CCs, using the config file.
"""
global cc_uri_sorted, cc_map, uri_to_cc
conf = snap_config.get_instance()
cc_conf = conf.get_section("component_container")
for cc_name in cc_conf:
# The server's URI is either specified by 'cc_proxy_uri', or in its
# absense, is a combination of 'cc_hostname' and 'cc_port'.
if ("cc_port" not in cc_conf[cc_name]) or (not cc_conf[cc_name]["cc_port"]):
raise SnapObjNotFoundError("Config file does not specify a port for CC '%s'" % cc_name)
if ("cc_proxy_uri" not in cc_conf[cc_name]) or (not cc_conf[cc_name]["cc_proxy_uri"]):
if ("cc_hostname" not in cc_conf[cc_name]) or (not cc_conf[cc_name]["cc_hostname"]):
raise SnapObjNotFoundError("Config file does not specify a proxy-URI or hostname for CC '%s'" % cc_name)
cc_uri = "http://%s:%s" % (cc_conf[cc_name]["cc_hostname"], cc_conf[cc_name]["cc_port"])
else:
cc_uri = cc_conf[cc_name]["cc_proxy_uri"]
parsed_uri = urlparse.urlparse(cc_uri)
if snap_http_lib.is_localhost(parsed_uri[1].split(":")[0]):
server.log(snap_log.LEVEL_WARN,
"CC '%s' hostname is set to '%s'. Network capabilities will be restricted."
% (cc_name, cc_uri))
if "cc_address" in cc_conf[cc_name] and snap_http_lib.is_localhost(cc_conf[cc_name]["cc_address"]):
server.log(snap_log.LEVEL_WARN,
"CC '%s' configuration parameter 'cc_address' is set to '%s'. Network capabilities will be restricted."
% (cc_name, cc_uri))
cc_map[cc_name] = {"uri" : cc_uri,
"cc_token" : "",
"checkin_time" : None
}
uri_to_cc[cc_uri] = cc_name
cc_uri_sorted = uri_to_cc.keys()
cc_uri_sorted.sort(lambda x, y: -cmp(len(x), len(y)))
def cc_register(http_req):
"""
Register a CC that has just come online.
This function notes the CC name and the token that should be
used to send requests to the CC. The CC uses the token as a
security measure to prevent anyone other than the main server
from requesting services from it. The token must be set as
the value of the header entry X-Snapi-cc-token, in every request
that is sent to the CC from the server.
"""
global _has_been_initialized
try:
request_dict = http_req.input.next()
except StopIteration:
return RhResponse(http_req.BAD_REQUEST, "Request body missing")
for k in (keys.CC_TOKEN, keys.CC_NAME):
if k not in request_dict:
return RhResponse(http_req.BAD_REQUEST, "Request body missing \"%s\"" % k)
cc_name = request_dict[keys.CC_NAME]
with _lock:
if cc_name not in cc_map:
return RhResponse(http_req.BAD_REQUEST, "CC %s is not configured in the server" % cc_name)
cc_map[cc_name]["cc_token"] = request_dict[keys.CC_TOKEN]
cc_map[cc_name]["checkin_time"] = time.time()
# Reconstruct the cc_token_list that is redundantly stored in the server for easy access.
server.cc_token_list = []
for v in cc_map.values():
server.cc_token_list.append(v["cc_token"])
# Now, write the config file out to CC.
conf = snap_config.get_instance()
cc_conf = conf.get_section("component_container")
if cc_name not in cc_conf:
# The CC name specified, does not exist in our config file.
return RhResponse(404, "The config for specified component container %s not found" % cc_name)
# Send the config section, and remember that at leat one
# of the CCs has been initialized.
cc_conf[cc_name]["runtime_entry_timeout"] = server.config.get_section("main")["runtime_entry_timeout"]
_has_been_initialized = True
return RhResponse(200, cc_conf[cc_name])
def is_ready():
"""
Return True if we have at least one CC initialized.
This allows the server to indicate to other modules whether
it is ready to run pipelines or not.
@return: Flag indicating whether we have at least one CC.
@rtype: bool
"""
return _has_been_initialized
def get_token_by_name(cc_name):
"""
Get CC token for the specified CC name.
@param cc_name: Name of the CC.
@type cc_name: string
@return: The token for the CC. None, if no such CC entry was found.
@rtype: string
"""
with _lock:
if cc_name not in cc_map:
return None
return cc_map[cc_name]["cc_token"]
def get_token_by_uri(uri):
"""
Find the CC to which the uri refers to (by doing prefix match) and return the CC token for that CC.
@param uri: URI being looked up
@type uri: string
@return: The token for that CC. None, if no matching URI was found.
@rtype: string
"""
uri = uri.lower()
with _lock:
for u in cc_uri_sorted:
# Should be the longest uri match
if uri.startswith(u):
return cc_map[uri_to_cc[u]]["cc_token"]
return None
|