Exemplo n.º 1
0
    def __init__(self, config, logger):
        self.config = config
        self.log = logger

        conn_sections = []
        try:
            conn_sections = [
                section for section in config.topLevels()
                if section not in ['Service']
            ]
            if len(conn_sections) != 2:
                raise ConfigurationError(
                    'Config does not contain two connection sections')
        except Exception:
            raise ConfigurationError(
                'Config file lacks sufficient information for BLDConnector')

        self.agicen_conn = None
        self.bld_conn = None

        self.bld_name = [
            name for name in conn_sections
            if not name.startswith('AgileCentral')
        ][0]
        self.log.info("Agile Central BLD Connector for %s, version %s" %
                      (self.bld_name, __version__))
        uname_fields = platform.uname()
        self.log.info("Python platform: %s %s" %
                      (uname_fields[0], uname_fields[2]))
        self.log.info("Python  version: %s" % sys.version.split()[0])

        self.internalizeConfig(config)

        droid = ClassLoader()
        agicen_conn_class_name = config.connectionClassName('AgileCentral')
        bld_conn_class_name = config.connectionClassName(self.bld_name)

        try:
            self.agicen_conn_class = droid.loadConnectionClass(
                agicen_conn_class_name, pkgdir=ARCHITECTURE_PKG)
        except Exception as msg:
            raise FatalError(
                'Unable to load AgileCentralBLDConnection class, %s' % msg)
        try:
            self.bld_conn_class = droid.loadConnectionClass(
                bld_conn_class_name, pkgdir=ARCHITECTURE_PKG)
        except Exception as msg:
            raise FatalError('Unable to load %sConnection class, %s' %
                             (self.bld_name, msg))

        self.establishConnections()

        if not self.validate(
        ):  # basically just calls validate on both connection instances
            raise ConfigurationError("Validation failed")
        self.log.info(
            "Initialization complete: Delegate connections operational, ready for scan/reflect ops"
        )
Exemplo n.º 2
0
    def connectionClassName(self, section_name):
        if section_name not in self.config:
            raise ConfigurationError('Attempt to identify connection class name for %s, operation not supported'% section_name)
        if section_name not in ['AgileCentral', self.bld_header]:
            raise ConfigurationError('Candidate connection class name "%s" not viable for operation'% section_name)
        section = self.config[section_name]
        if 'Class' in section:
            class_name = section['Class']
        else:
            class_name = 'AgileCentralConnection' 
            if section_name != 'AgileCentral':
                class_name = '%sConnection' % self.bld_header

        return class_name
Exemplo n.º 3
0
    def getConfiguration(self, config_file):
        try:
            config = Konfabulator(config_file, self.log)
        except NonFatalConfigurationError as msg:
            pass  # info for this will have already been logged or blurted
        except Exception as msg:
            raise ConfigurationError(msg)
        svc_conf = config.topLevel('Service')
        self.preview = False
        if svc_conf and svc_conf.get('Preview', None) == True:
            self.preview = True
        self.log_level = 'Info'
        if svc_conf:
            ll = svc_conf.get('LogLevel', 'Info').title()
            if ll in ['Fatal', 'Error', 'Warn', 'Info', 'Debug']:
                self.log_level = ll
                self.log.setLevel(self.log_level)
            else:
                pass  # bad LogLevel specified
            #if 'PostBatchExtension' in svc_conf:
            #    pba_class_name = svc_conf['PostBatchExtension']
            #    pba_class = ExtensionLoader().getExtension(pba_class_name)
            #    self.extension['PostBatch'] = pba_class()

        return config
Exemplo n.º 4
0
def test_detect_same_name_projects():
    of = sh.OutputFile('test.log')
    filename = ('config/temp.yml')
    logger, tkonf = sh.setup_test_config(filename)
    assert tkonf.topLevels() == ['AgileCentral', 'Jenkins', 'Service']
    tkonf.remove_from_container({'View': 'Shoreline'})
    tkonf.remove_from_container({'Job': 'truculent elk medallions'})
    assert not tkonf.has_item('View', 'Shoreline')
    assert not tkonf.has_item('Job', 'truculent elk medallions')
    ac_conf = tkonf.topLevel('AgileCentral')
    jenk_conf = tkonf.topLevel('Jenkins')
    bc = bsh.BLDConnector(tkonf, logger)
    agicen = bc.agicen_conn.agicen
    workspace_name = ac_conf['Workspace']
    project_name = jenk_conf['AgileCentral_DefaultBuildProject']
    response = agicen.get('Project',
                          fetch='Name',
                          workspace=workspace_name,
                          projectScopeDown=True,
                          pagesize=200)
    if response.errors or response.resultCount == 0:
        raise ConfigurationError(
            'Unable to locate a Project with the name: %s in the target Workspace'
            % project_name)

    assert bc.agicen_conn.duplicated_project_names[0] == 'Salamandra'
Exemplo n.º 5
0
    def run(self):
        own_lock = False
        build_system_name = self.identifyBuildSystemName()
        self.proclaim_existence(build_system_name)
        own_lock = self.acquireLock()

        try:
            for config_file in self.config_file_names:
                config_file_path = self.find_config_file(config_file)
                if not config_file_path:
                    raise ConfigurationError(
                        "No config file for '%s' found in the config subdir" %
                        config_file)
                lf_name = "log/%s.log" % config_file.replace(
                    '.yml', '').replace('_config', '')
                self.log = ActivityLogger(lf_name)
                logAllExceptions(True, self.log)
                self._operateService(config_file_path)
        except Exception as msg:
            self.log.error(msg)
        finally:
            try:
                if own_lock: self.releaseLock()
            except Exception as msg:
                raise OperationalError(
                    "ERROR: unable to remove lock file '%s', %s" %
                    (LOCK_FILE, msg))
        self.log.info('run completed')
Exemplo n.º 6
0
    def __priorArt(self):
        conf = self.config
        conf_top_level_keys = conf.keys()
        conns = [key for key in conf.keys() if key not in ['Service']]
        if len(conns) != 2:
            self.log.fatal('Configuration does not specify exactly 2 Connections')
            return None, None

        with open(self.config_file, 'r') as cf:
            lines = cf.readlines()
            conn_lines = []
            for line in lines:
                if line.startswith(' ') or line.startswith('#'):
                    continue
                if line.strip().split(':')[0] in ['Service']:
                    continue
                if ':' not in line.strip():
                    continue
                conn_lines.append(line.strip().split(':')[0])
                
        if len(conn_lines) != 2:
            problem = 'Configuration file does not conform to spec, %d Connection sections found'
            self.log.fatal(problem % len(conn_lines))

        agicen_conn_name = conn_lines[0]
        bld_conn_name    = conn_lines[1]

        if not agicen_conn_name.startswith('AgileCentral'):
            problem = 'Unexpected name for initial connection in config, expected AgileCentral'
            raise ConfigurationError(problem)
Exemplo n.º 7
0
 def topLevel(self, section_name):
     if section_name == 'BLD':
         section_name = [name for name in self.top_level_sequence 
                               if name not in ['AgileCentral', 'Service']][0]
         
     if section_name in self.top_level_sequence and section_name in self.config:
         return self.config[section_name]
     else:
         problem = 'Attempt to retrieve non-existent top level config section for %s'
         raise ConfigurationError(problem  % section_name)
Exemplo n.º 8
0
    def connect(self):
        """
        """
        self.log.info("Connecting to Jenkins")

        self.backend_version = self._getJenkinsVersion()
        self.log.info("Connected to Jenkins server: %s running at version %s" %
                      (self.server, self.backend_version))
        self.log.info("Url: %s" % self.base_url)
        self.job_class_exists = self._checkJenkinsJobClassProp()
        if not self.job_class_exists:
            msg = "The Jenkins REST API doesn't return a _class property in the response. Update to Jenkins 2.2 or greater to use this connector"
            raise ConfigurationError(msg)
        self.obtainJenkinsInventory()
        return True
Exemplo n.º 9
0
    def __init__(self, args):
        """
            An instance of this class is responsible for basic command line parsing,
            pulling off the name of the target config file.
            Once that item is taken care of, the instance obtains an instance of a
            Konfabulator, a AuxiliaryClassLoader instance and and instance of an BLDConnector.
            The Konfabulator is delegated the task of reading the config file, the AuxiliaryClassLoader
            is delegated the task of pulling in any Extension classes.
            These instances are then provided to the BuildConnector instance.
            This instance then directs the BuildConnector instance to obtain unrecorded builds 
            from the target Build/CI system and reflect them in the Agile Central server.
        """
        if len(args) < 1:
            problem = (
                "Insufficient command line args, must be at least a config file name."
            )
            raise ConfigurationError(problem)

        self.default_log_file_name = True

        # this only allows a logfile spec of --logfile=<some_file_name>
        # TODO: consider allowing additional syntax  logfile=foo.log or --logfile foo.log
        log_spec = [arg for arg in args if arg.startswith('--logfile=')]
        if log_spec:
            self.logfile_name = log_spec[0].replace('--logfile=', '')
            self.default_log_file_name = False
            for spec in log_spec:
                args = [arg for arg in args if arg != spec]

        self.config_file_names = args
        if self.default_log_file_name:  # set it to first config file minus any '_config.yml' portion
            self.first_config = self.config_file_names[0]
            self.logfile_name = "log/%s.log" % self.first_config.replace(
                '.yml', '').replace('_config', '')
            try:
                if not os.path.exists('log'):
                    os.makedirs('log')
            except Exception as msg:
                sys.stderr.write(
                    "Unable to locate or create the log sub-directory, %s\n" %
                    msg)
                raise Exception

        self.log = ActivityLogger(self.logfile_name)
        logAllExceptions(True, self.log)
        self.preview = False
        self.connector = None
        self.extension = {}
Exemplo n.º 10
0
    def internalizeConfig(self, config):
        super().internalizeConfig(config)

        server = config.get('Server', 'rally1.rallydev.com')
        if 'http' in server.lower() or '/slm' in server.lower():
            self.log.error(
                self,
                "AgileCentral URL should be in the form 'rally1.rallydev.com'")
        self.server = server

        self.url = "https://%s/slm" % server
        self.port = config.get('Port', '443')
        self.apikey = config.get("APIKey", config.get("API_Key", None))
        self.workspace_name = config.get("Workspace", None)
        self.project_name = config.get(
            "Project", None)  # This gets bled in by the BLDConnector
        self.restapi_debug = config.get("Debug", False)
        self.restapi_logger = self.log

        self.proxy = None
        if self.proxy_server:
            self.proxy = "%s://%s:%s" % (self.proxy_protocol,
                                         self.proxy_server, self.proxy_port)
            if self.proxy_username and self.proxy_password:
                self.proxy = "%s://%s:%s@%s:%s" % (
                    self.proxy_protocol, self.proxy_username,
                    self.proxy_password, self.proxy_server, self.proxy_port)

        valid_config_items = [
            'Server', 'Port', 'APIKey', 'Workspace', 'Project', 'Username',
            'Password', 'ProxyProtocol', 'ProxyServer', 'ProxyPort',
            'ProxyUser', 'ProxyUsername', 'ProxyPassword', 'Debug', 'Lookback'
        ]
        invalid_config_items = [
            item for item in config.keys() if item not in valid_config_items
        ]
        if invalid_config_items:
            problem = "AgileCentral section of the config contained these invalid entries: %s" % ", ".join(
                invalid_config_items)
            raise ConfigurationError(problem)
Exemplo n.º 11
0
    def getViewFolders(self, view):
        if view not in self.all_views:
            raise ConfigurationError(
                "specified view '%s' not present in list of existing Jenkins views"
                % view['View'])

        urlovals = {'prefix': self.base_url, 'view': quote(view)}
        view_job_folders_url = VIEW_FOLDERS_URL.format(**urlovals)
        #self.log.debug("view: %s  req_url: %s" % (view, view_job_folders_url))
        response = requests.get(view_job_folders_url, auth=self.creds)
        jenk_stuff = response.json()
        jenk_jobs = [job for job in jenk_stuff.get('jobs', None)]
        view_folders = {}
        #self.log.debug('Folders:')
        for job in jenk_jobs:
            if not 'jobs' in job:
                continue
            jenkins_folder = JenkinsJobsFolder(job['name'], job['url'],
                                               job['jobs'])
            view_folders[jenkins_folder.name] = jenkins_folder
            #self.log.debug(jenkins_folder)
        return view_folders
Exemplo n.º 12
0
    def acquireLock(self):
        """
            Check for conditions to proceed based on lock file absence/presence status.
            Acquisition of the lock is a green-light to proceed.
            Failure to acquire the lock prevents any further operation.
        """
        if LockFile.exists(LOCK_FILE):
            self.log.warning("A %s file exists" % LOCK_FILE)
            locker = LockFile.currentLockHolder(LOCK_FILE)
            if not LockFile.lockerIsRunning(LOCK_FILE, locker):
                message = (
                    "A prior connector process (%s) did not clean up "
                    "the lock file on termination, proceeding with this run")
                self.log.warning(message % locker)
            else:
                self.log.error(
                    "Another connector process [%s] is still running, unable to proceed"
                    % locker)
                raise ConfigurationError(
                    "Simultaneous processes for this connector are prohibited")

        LockFile.createLock(LOCK_FILE)
        return True
Exemplo n.º 13
0
    def _getJenkinsVersion(self):
        version = None
        jenkins_url = "%s/manage" % self.base_url
        self.log.debug(jenkins_url)
        try:
            response = requests.get(jenkins_url,
                                    auth=self.creds,
                                    proxies=self.http_proxy)
        except Exception as msg:
            self.log.error(msg)
        if response.status_code >= 300:
            mo = re.search(r'<title>.*?</title>', response.text)
            msg = mo.group(0) if mo else 'Connection error to Jenkins'
            raise ConfigurationError('%s  status_code: %s' %
                                     (msg, response.status_code))

        # self.log.debug(response.headers)
        extract = [
            value for key, value in response.headers.items()
            if key.lower() == 'x-jenkins'
        ]
        if extract:
            version = extract.pop(0)
        return version
Exemplo n.º 14
0
    def connect(self):
        if self.proxy:
            self.log.info("Proxy for AgileCentral connection:  %s" %
                          self.proxy)
            os.environ['HTTPS_PROXY'] = self.proxy

        self.log.info("Connecting to AgileCentral")
        custom_headers = self.get_custom_headers()

        try:
            before = time.time()
            ##            print("")
            ##            print("before call to pyral.Rally(): %s    using workspace name: %s" % (before, self.workspace_name))
            ##            print("   credentials:  username |%s|  password |%s|  apikey |%s|" % (self.username, self.password, self.apikey))
            self.agicen = Rally(self.server,
                                user=self.username,
                                password=self.password,
                                apikey=self.apikey,
                                workspace=self.workspace_name,
                                project=self.project_name,
                                version=self.rallyWSAPIVersion(),
                                http_headers=custom_headers,
                                server_ping=False,
                                isolated_workspace=True,
                                logger=self.restapi_logger,
                                warn=False,
                                debug=True)
            after = time.time()
            ##            print("after  call to pyral.Rally(): %s" % after)
            ##            print("initial Rally connect elapsed time: %6.3f  seconds" % (after - before))
            ##            sys.stdout.flush()
            ##
            if self.restapi_debug:
                self.agicen.enableLogging('agicen_builds.log')
        except Exception as msg:
            raise ConfigurationError("Unable to connect to Agile Central at %s: %s" % \
                                         (self.server, msg))
        self.log.info("Connected to Agile Central server: %s" % self.server)

        ##        before = time.time()
        # verify the given workspace name exists
        ##        print("")
        ##        print("before call to agicen.getWorkspaces: %s" % before)
        all_workspaces = self.agicen.getWorkspaces()
        ##        after = time.time()
        ##        print("after  call to agicen.getWorkspaces: %s" % after)
        ##        print("agicen.getWorkspaces elapsed time: %6.3f  seconds" % (after - before))

        valid = [
            wksp for wksp in all_workspaces if wksp.Name == self.workspace_name
        ]
        if not valid:
            problem = "Specified Workspace: '%s' not in list of workspaces " + \
                      "available for your credentials as user: %s"
            raise ConfigurationError(problem %
                                     (self.workspace_name, self.username))
        self.log.info("    Workspace: %s" % self.workspace_name)
        self.log.info("    Project  : %s" % self.project_name)
        wksp = self.agicen.getWorkspace()
        prjt = self.agicen.getProject()
        self.workspace_ref = wksp.ref
        self.project_ref = prjt.ref

        # find all of the Projects under the AgileCentral_Project
        ##        before = time.time()
        ##        print("")
        ##        print("before call to agicen get Project: %s" % before)
        response = self.agicen.get('Project',
                                   fetch='Name',
                                   workspace=self.workspace_name,
                                   project=self.project_name,
                                   projectScopeDown=True,
                                   pagesize=200)
        if response.errors or response.resultCount == 0:
            raise ConfigurationError(
                'Unable to locate a Project with the name: %s in the target Workspace'
                % self.project_name)

        # detect any duplicate project names
        self.project_bucket = {}
        for proj in response:
            if proj.Name not in self.project_bucket:
                self.project_bucket[proj.Name] = 0
            self.project_bucket[proj.Name] += 1
        self.duplicated_project_names = [
            p for p, c in self.project_bucket.items() if c != 1
        ]

        project_names = [proj.Name for proj in response]
        ##        after = time.time()
        ##        print("after  call to agicen get Project: %s" % after)
        ##        print("agicen.get Project  elapsed time: %6.3f  seconds  for  %d Projects" % ((after - before), len(project_names)))
        ##        print("")
        self.log.info("    %d sub-projects" % len(project_names))

        return True
Exemplo n.º 15
0
    def validateProjects(self, target_projects):
        """
            make requests to AgileCentral to retrieve basic info for each project in target_projects.
            If any project name in target_projects does NOT have a corresponding project in AgileCentral
            raise and Exception naming the offending project.
        """
        try:
            mep_projects = list(
                set([
                    project for project in target_projects if ' // ' in project
                ]))
        except Exception as msg:
            raise OperationalError(
                "%s %s" %
                ("error in agicen_bld_connection.py for getting mep_projects",
                 msg))
        try:
            non_mep_projects = list(
                set([
                    project for project in target_projects
                    if ' // ' not in project
                ]))
        except Exception as msg:
            raise OperationalError("%s %s" % (
                "error in agicen_bld_connection.py for getting non_mep_projects",
                msg))
        query = self._construct_ored_Name_query(non_mep_projects)
        response = self.agicen.get('Project',
                                   fetch='Name,ObjectID',
                                   query=query,
                                   workspace=self.workspace_name,
                                   project=None,
                                   projectScopeDown=True,
                                   pagesize=200)
        if response.errors or response.resultCount == 0:
            raise ConfigurationError(
                'Unable to locate a Project with the name: %s in the target Workspace: %s'
                % (self.project_name, self.workspace_name))

        found_projects = [project for project in response]
        try:
            found_project_names = list(set([p.Name for p in found_projects]))
        except Exception as msg:
            raise OperationalError("%s %s" % (
                "error in agicen_bld_connection.py for getting found_project_names",
                msg))
        bogus = [
            name for name in target_projects if name not in found_project_names
        ]
        try:
            real_bogus = set(bogus) - set(mep_projects)
        except Exception as msg:
            raise OperationalError(
                "%s %s" %
                ("error in agicen_bld_connection.py for getting real_bogus",
                 msg))
        if real_bogus:
            problem = "These projects mentioned in the config were not located in AgileCentral Workspace %s: %s" % (
                self.workspace_name, ",".join(real_bogus))
            self.log.error(problem)
            return False

        #deal with the mep_projects
        for mep in mep_projects:
            proj = self.agicen.getProject(mep)
            if proj:
                found_projects.append(proj)

        self._project_cache = {proj.Name: proj.ref for proj in found_projects}
        return True
Exemplo n.º 16
0
    def internalizeConfig(self, config):
        super().internalizeConfig(config)
        self.protocol = config.get('Protocol', 'http')
        self.server = config.get('Server', socket.gethostname())
        self.port = config.get('Port', 8080)
        self.prefix = config.get("Prefix", '')
        #self.user       = config.get("Username", '')
        #self.password   = config.get("Password", '')
        self.api_token = config.get("API_Token", '')
        self.debug = config.get("Debug", False)
        self.max_items = config.get("MaxItems", 1000)
        self.full_folder_path = config.get("FullFolderPath", False)
        self.ac_project = config.get("AgileCentral_DefaultBuildProject", None)
        self.views = config.get("Views", [])
        self.jobs = config.get("Jobs", [])
        self.folders = config.get("Folders", [])
        self.base_url = "{0}://{1}:{2}".format(self.protocol, self.server,
                                               self.port)
        self.all_views = []
        self.all_jobs = []
        self.view_folders = {}
        self.maxDepth = config.get('MaxDepth', 1) + 2
        if self.username:
            if self.api_token:
                cred = self.api_token
            else:
                cred = self.password
            self.creds = (self.username, cred)
        else:
            self.creds = None

        #https_proxy = os.environ.get('https_proxy', None) or os.environ.get('HTTPS_PROXY', None)
        #if https_proxy not in ["", None]:
        #    self.log.info("Proxy for Jenkins connection:  %s" % https_proxy)

        self.http_proxy = {}
        if self.proxy_server:
            proxy = "%s://%s:%s" % (self.proxy_protocol, self.proxy_server,
                                    self.proxy_port)
            if self.proxy_username and self.proxy_password:
                proxy = "%s://%s:%s@%s:%s" % (
                    self.proxy_protocol, self.proxy_username,
                    self.proxy_password, self.proxy_server, self.proxy_port)
            self.http_proxy = {self.protocol: proxy}
            self.log.info("Proxy for Jenkins connection:  %s" % proxy)

        valid_config_items = [
            'Server',
            'Protocol',
            'Prefix',
            'Port',
            'API_Token',
            'MaxItems',
            'Username',
            'User',
            'Password',
            'ProxyProtocol',
            'ProxyServer',
            'ProxyPort',
            'ProxyUser',
            'ProxyUsername',
            'ProxyPassword',
            'Debug',
            'Lookback',
            'AgileCentral_DefaultBuildProject',
            'MaxDepth',
            'FullFolderPath',
            'Views',
            'Jobs',
            'Folders',
        ]

        invalid_config_items = [
            item for item in config.keys() if item not in valid_config_items
        ]
        if invalid_config_items:
            problem = "Jenkins section of the config contained these invalid entries: %s" % ", ".join(
                invalid_config_items)
            raise ConfigurationError(problem)
Exemplo n.º 17
0
    def internalizeConfig(self, config):
        self.agicen_conf = config.topLevel('AgileCentral')
        self.bld_conf = config.topLevel(self.bld_name)
        if not 'AgileCentral_DefaultBuildProject' in self.bld_conf:
            msg = "The Jenkins section of the config is missing AgileCentral_DefaultBuildProject property"
            raise ConfigurationError(msg)
        if not self.bld_conf[
                'AgileCentral_DefaultBuildProject']:  # but no value exists for this...
            msg = "The Jenkins section of the config is missing a value for AgileCentral_DefaultBuildProject property"
            raise ConfigurationError(msg)
        self.agicen_conf['Project'] = self.bld_conf[
            'AgileCentral_DefaultBuildProject']
        self.svc_conf = config.topLevel('Service')
        self.max_builds = self.svc_conf.get('MaxBuilds', 20)
        default_project = self.agicen_conf['Project']

        valid_config_items = [
            'Preview', 'LogLevel', 'MaxBuilds', 'ShowVCSData'
        ]
        svc_conf = config.topLevel('Service')
        invalid_config_items = [
            item for item in svc_conf.keys() if item not in valid_config_items
        ]
        if invalid_config_items:
            problem = "Service section of the config contained these invalid entries: %s" % ", ".join(
                invalid_config_items)
            raise ConfigurationError(problem)

        # create a list of AgileCentral_Project values, start with the default project value
        # and then add add as you see overrides in the config.
        # eventually, we'll strip out any duplicates
        self.target_projects = [
            default_project
        ]  # the default project always is considered for obtaining build info

        if "Views" in self.bld_conf:
            self.views = self.bld_conf["Views"]
            if not self.views:
                msg = "Views section of the config is empty"
                raise ConfigurationError(msg)
            for view in self.views:
                view_name = view['View']
                self.target_projects.append(
                    view.get('AgileCentral_Project', default_project))

        if "Folders" in self.bld_conf:
            self.folders = self.bld_conf["Folders"]
            if not self.folders:
                msg = "Folders section of the config is empty"
                raise ConfigurationError(msg)
            for folder_conf in self.folders:
                folder_display_name = folder_conf['Folder']
                self.target_projects.append(
                    folder_conf.get('AgileCentral_Project', default_project))

        if "Jobs" in self.bld_conf:
            self.jobs = self.bld_conf["Jobs"]
            if not self.jobs:
                msg = "Jobs section of the config is empty"
                raise ConfigurationError(msg)
            for job in self.jobs:
                job_name = job['Job']
                self.target_projects.append(
                    job.get('AgileCentral_Project', default_project))
        self.target_projects = list(set(
            self.target_projects))  # to obtain unique project names
Exemplo n.º 18
0
    def __init__(self, config_file_name, logger):
        self.config_file_name = config_file_name
        self.log = logger
        self.top_level_sequence = []

        # check for existence, file-ness, readability of config_file_name
        if not os.path.exists(config_file_name):
            raise ConfigurationError('config file: %s not found' % config_file_name)
        if not os.path.isfile(config_file_name):
            raise ConfigurationError('config file: %s is not a file' % config_file_name)
        if not os.access(config_file_name, os.F_OK | os.R_OK):
            raise ConfigurationError('config file: %s not a readable file' % config_file_name)

        content = []
        try:
            cf = open(config_file_name, 'r', encoding='utf-8')
        except IOError as msg:
            raise ConfigurationError('Unable to open %s for reading, %s' % (config_file_name, msg))
        content = cf.read()
        self.content = content
        cf.close()

        basic_sanity, problem = self._checkConfigFileContentSanity()
        if not basic_sanity:
            raise ConfigurationError('Config file (%s) syntax/structure is incorrect, %s' % (config_file_name, problem), logger=logger)

        try:
            complete_config = yaml.load(content)
            top_key = list(complete_config.keys())[0]
            self.config = complete_config[top_key]
        except Exception as msg:
            raise ConfigurationError('Unable to parse %s successfully, %s' % (config_file_name, msg), logger=logger)

        conf_lines = [line for line in content.split('\n') if line and not re.search(r'^\s*#', line)]
        connector_header = [line for line in conf_lines if re.search(r'^[A-Z][A-Za-z_]+.+\s*:', line)]
        section_headers  = [line for line in conf_lines if re.search(r'^    [A-Z][A-Za-z_]+.+\s*:', line)]
##
        #print(repr(self.config))
##
        if len(section_headers) < 2:
            raise ConfigurationError('Insufficient content in config file: %s' % config_file_name)
        if len(section_headers) > 3:
            raise NonFatalConfigurationError('Excess content in config file: %s' % config_file_name)

        self.agicen_header = section_headers.pop(0).strip().replace(':', '')
        if not self.agicen_header.startswith('AgileCentral'):
            raise ConfigurationError('First section in config file must be AgileCentral section')
        self.top_level_sequence.append('AgileCentral')

        self.bld_header = section_headers.pop(0).strip().replace(':', '')
        if self.bld_header not in ['Jenkins']:
            raise ConfigurationError('Second section in config file must identify a known BLD identifier')
        self.top_level_sequence.append(self.bld_header)

        # set up defaults for the Service section if that section isn't in the config file
        if 'Service' not in self.config:
            self.config['Service'] = {}
            self.config['Service']['LogLevel']    = 'Info'
            self.config['Service']['Preview']     = False
            self.config['Service']['MaxBuilds']   = 50
            self.config['Service']['ShowVCSData'] = True
            self.config['Service']['PostBatchExtension']  = None

        while section_headers:
            header = section_headers.pop(0).replace(':', '').strip()
            try:
                if header not in ['Service']:
                    problem = 'config section header "%s" not recognized, ignored...' % header
                    raise ConfigurationError(problem)
                else:
                    self.top_level_sequence.append(header)
            except ConfigurationError as msg:
                pass

        # defuzz the passwords if they are fuzzed, and if they are not, fuzz them in the file
        self.defuzzPasswords()
Exemplo n.º 19
0
    def fuzzPassword(self, conn_section, clear_text_password):
        """
            check to see whether or not the Password entries in one or both of the connection
            sections are not encoded.  If not, encode them and write out the config file
            changing *only* those two entries:
        """
        if Fuzzer.isEncoded(clear_text_password):
            return False

        encoded_password = Fuzzer.encode(clear_text_password)
            
        conf_lines = []
        try:
            cf = open(self.config_file_name, 'r', encoding='utf-8')
        except IOError as msg:
            raise ConfigurationError('Unable to open %s for reading, %s' % (self.config_file_name, msg))
        conf_lines = cf.readlines()
        cf.close()

        out_lines = []
        ix = 0

        # objective:   Find index of conn_section entry in conf_lines
        #              then find index of next occurring Password : xxxx entry
        #              substitute entry for Password : current with Password : encoded_password
##
##        print "fuzzPassword, conn_section: %s" % conn_section
##        print "conf_lines:\n%s" % "\n".join(conf_lines)
##        print "-----------------------------------------------------"
##
        hits = [ix for ix, line in enumerate(conf_lines) if re.search('^\s+%s\s*:' % conn_section, line)]
        section_ix = hits[0]
        hits = [ix for ix, line in enumerate(conf_lines) if re.search('^\s+Password\s*:\s*', line) and ix > section_ix]
        if hits:
            pwent_ix = hits[0]
            conf_lines[pwent_ix] = '        Password  :  %s\n' % encoded_password

        enc_file_name = '%s.pwenc' % self.config_file_name
        enf = open(enc_file_name, 'w', encoding='utf-8')
        enf.write(''.join(conf_lines))
        enf.close()
       
        bkup_name = "%s.bak" % self.config_file_name
        try:
            shutil.copy2(self.config_file_name, bkup_name)
        except Exception as msg:
            self.log.warn("Unable to write a temporary backup file '%s' with config info: %s" % (bkup_name, msg))
            return False

        try:
            os.remove(self.config_file_name)
        except Exception as msg:
            self.log.warn("Unable to remove config file prior to replacement with password encoded version of the file: %s" % msg)
            return False

        try:
            os.rename(enc_file_name, self.config_file_name)
        except Exception as msg:
            self.log.error("Unable to rename config file with password encoded to standard config filename of %s: %s" % (self.config_file_name, msg))
            return False

        try:
            os.remove(bkup_name)
        except Exception as msg:
            self.log.warn("Unable to remove temporary backup file for config: %s" % msg)
            return False

        return True