#!/usr/bin/env python3 # -*- coding: utf-8 -*- # ============================================================================== # Copyright and license info is available in the LICENSE file included with # the Server Deployment Package (SDP), and also available online: # https://swarm.workshop.perforce.com/projects/perforce-software-sdp/view/main/LICENSE # ------------------------------------------------------------------------------ """ NAME: ControlFetch.py DESCRIPTION: Trigger to only allow certain users/groups to perform a "p4 fetch" To install, add a line to your Perforce triggers table like the following: control-fetch command pre-rmt-Fetch "python /p4/common/bin/triggers/ControlFetch.py -c config.yaml -p %serverport% -u perforce %user% %formfile% " or (if server is standard SDP and has appropriate environment defaults for P4PORT and P4USER): control-fetch command pre-rmt-Fetch "python /p4/common/bin/triggers/ControlFetch.py -c /p4/common/config/Workflow.yaml %user% %formfile% " You may need to provide the full path to python executable, or edit the path to the trigger. Also, don't forget to make the file executable, and setup the YAML configuration file (specified by -c parameter above): # ------------------------------------------ # config.yaml # msg_fetch_not_allowed: An array of lines for the message # For legibility it is good to have the first line blank msg_fetch_not_allowed: - "" - "You are not allowed to perform 'p4 fetch' on this server." # can_fetch: An array of user or group names who are allowed to perform fetch fetch_allowed_users_or_groups: - user1 - group1 - group2 """ # Python 2.7/3.3 compatibility. from __future__ import print_function import sys from WorkflowTriggers import WorkflowTrigger, GroupMemberChecker import os import re trigger_name = os.path.basename(os.path.splitext(__file__)[0]) class ControlFetch(WorkflowTrigger): """See module doc string for details""" def __init__(self, *args, **kwargs): WorkflowTrigger.__init__(self, **kwargs) self.parse_args(__doc__, args) def add_parse_args(self, parser): """Specific args for this trigger - also calls super class to add common trigger args""" parser.add_argument('-c', '--config-file', default=None, help="Configuration file for trigger. Default: ControlFetch.yaml") parser.add_argument('user', help="User carrying out the command - %%user%% argument from triggers entry.") super(ControlFetch, self).add_parse_args(parser) def get_fetch_project(self, config, stream_name): for prj in config['can_fetch']: if not 'name' in prj or not 'stream_paths' in prj: continue pats = [] for r in prj['stream_paths']: try: pats.append(re.compile(r)) except: self.logger.error("Invalid python regex: %s in prj %s" % (r, str(prj))) for pat in pats: if pat.search(stream_name): self.logger.debug("%s: stream matched: %s" % (trigger_name, stream_name)) return prj return {} def run(self): """Runs trigger""" try: self.logger.debug("%s: firing" % trigger_name) config = self.load_config(self.options.config_file) errors = [] for k in "fetch_allowed_users_or_groups msg_fetch_not_allowed".split(): if k not in config: errors.append("Config file %s missing definition for %s" % (self.options.config_file, k)) if errors: msg = "%s: Invalid config file for trigger %s\n" % (trigger_name, str(errors)) self.message(msg) return 1 self.setupP4() self.p4.connect() # Now check for users and groups who are allowed to create streams gchk = GroupMemberChecker(self.p4) if gchk.IsMember(self.options.user, config['fetch_allowed_users_or_groups']): self.logger.debug("%s: User allowed to bypass trigger: %s" % (trigger_name, self.options.user)) return 0 err_msg = "\n".join(config['msg_fetch_not_allowed']) +\ "\nUser: %s" % self.options.user self.message(err_msg) self.logger.warning(err_msg) return 1 except Exception: return self.reportException() return 0 if __name__ == '__main__': """ Main Program""" trigger = ControlFetch(*sys.argv[1:]) sys.exit(trigger.run())