GitHub PullRequestReviewCommentEvent at 2014-04-07 17:51:29
Repository: origin-server
Actor: lnader
Payload: {"comment":{"url":"https://api.github.com/repos/openshift/origin-server/pulls/comments/11355946","id":11355946,"diff_hunk":"@@ -0,0 +1,491 @@\n+#!/usr/bin/env oo-ruby\n+\n+require 'optparse'\n+require 'ostruct'\n+require 'net-ldap'\n+require 'yaml'\n+\n+PATH = \"#{ENV['OPENSHIFT_BROKER_DIR'] || '/var/www/openshift/broker'}/config/environment\"\n+\n+class Command\n+\n+  def create(options)\n+    raise ArgumentError, \"Use -n or --name to specify a name\" if options.name.nil?\n+    env!(options)\n+    team = validate_and_create_team(options.name, options.maps_to)\n+    exit 0\n+  rescue OpenShift::UserException => ex\n+    puts \"Could not create team: #{ex.message}\"\n+    exit 1\n+  rescue ArgumentError\n+    warn $!\n+    1\n+  rescue => e\n+    exception e, \"Failed to create team: #{options.name}\"\n+    1\n+  end\n+\n+  def list(options)\n+    env!(options)\n+    \n+    teams = Team.where(owner_id: nil)\n+    teams.each do |team|\n+      puts \"#{team.name}  maps to:#{team.maps_to} global:#{team.owner_id.nil?} Members:#{team.members.count}\"\n+    end\n+    0\n+  rescue => e\n+    warn \"Failed to list teams\"\n+    warn e.message\n+    warn e.backtrace\n+    1\n+  end\n+  \n+  def show(options)\n+    raise ArgumentError, \"Use -n or --name to specify a name\" if options.name.nil?\n+    env!(options)\n+    puts \"Getting team: #{options.name} ...\"\n+    team = Team.find_by(name: options.name, owner_id: nil) rescue nil\n+    if team\n+      puts \"Name: #{team.name}\"\n+      puts \"Global: #{team.owner_id.nil?}\"\n+      puts \"Maps to: #{team.maps_to}\"\n+      puts \"Members:\"\n+      team.members.each {|m| puts \"\\tName:#{m.n}\"}\n+      0\n+    else\n+      puts \"Team: #{options.name} not found\"\n+      1\n+    end  \n+    0\n+  rescue ArgumentError\n+    warn $!\n+    1\n+  rescue => e\n+    exception e, \"Failed to show team: #{options.name}\"\n+    1\n+  end\n+\n+  def delete(options)\n+    raise ArgumentError, \"Use -n or --name to specify a name\" if options.name.nil?\n+    env!(options)\n+    puts \"Deleting team: #{options.name} ...\"\n+    team = Team.find_by(name: options.name, owner_id: nil) rescue nil\n+    if team\n+      team.destroy_team\n+      puts \"Team: #{options.name} deleted\"\n+      0\n+    else\n+      puts \"Team: #{options.name} not found\"\n+      1\n+    end\n+  rescue ArgumentError\n+    warn $!\n+    1\n+  rescue => e\n+    exception e, \"Failed to delete team: #{options.name}\"\n+    1\n+  end\n+  \n+  def sync_from_file(options)\n+    raise ArgumentError, \"Input file required. Use -i or --in-file to specify a file\" if options.in_file.nil?\n+    env!(options)\n+    in_file = File.open(\"#{options.in_file}\", \"r\")\n+    while (line = in_file.gets)\n+      object_type, command, params = line.split(\"|\").map(&:strip)\n+      params= params.split(\":\")\n+      puts \"#{object_type} #{command} #{params}\"\n+      case object_type\n+      when \"TEAM\"\n+        if command == \"ADD\"\n+          begin\n+            team = validate_and_create_team(params[0], params[1])\n+          rescue OpenShift::UserException => ex\n+            puts \"ERROR: Could not create team: #{ex.message}\"\n+          end\n+        elsif command == \"REMOVE\"\n+          begin\n+            team = Team.find_by(name: params[0], owner_id: nil)\n+            team.destroy_team\n+          rescue Exception => ex\n+            puts \"ERROR: Could not delete team: #{ex.message}\"\n+          end\n+        else\n+          puts \"ERROR: Command #{command} not available for #{object_type}\"\n+        end\n+      when \"USER\"\n+        if command == \"ADD\"\n+          user = CloudUser.find_or_create_by(login: params[0])\n+        else\n+          puts \"ERROR: Command #{command} not available for #{object_type}\"\n+        end\n+      when \"MEMBER\"\n+        team = Team.where(name: params[0], owner_id: nil).first\n+        if team.nil?\n+          puts \"ERROR: Could not find team: #{params[0]}\" if team.nil?\n+          next\n+        end\n+        user_names = params[1] ? params[1].split(\",\") : nil\n+        if user_names\n+          members_to_add = []\n+          user_names.each do |user_name|\n+            u = CloudUser.find_by(login: user_name) rescue nil\n+            if u.nil?\n+              puts \"ERROR: Could not find user: #{params[1]}\"\n+              next\n+            end\n+            members_to_add.push(u)\n+          end\n+          if command == \"ADD\"      \n+            team.add_members(members_to_add)\n+          elsif command == \"REMOVE\"\n+            members_to_remove = team.members.select {|m| user_names.include? m.n}\n+            team.remove_members(members_to_remove) \n+          else\n+            puts \"ERROR: Command #{command} not available for #{object_type}\"\n+          end\n+          team.save\n+          team.run_jobs\n+        end\n+      end\n+    end\n+    0\n+  rescue ArgumentError\n+    warn $!\n+    1\n+  rescue => e\n+    exception e, \"Failed to sync-from-file #{options.in_file}\"\n+    1\n+  end\n+\n+  def sync_to_file(options)\n+    raise ArgumentError, \"Path to config file required. Use --config-file to specify a file\" if options.config_file.nil?\n+    raise ArgumentError, \"Path to output file required. Use -o or --out-file to specify a file\" if options.out_file.nil?\n+    out_file = File.open(\"#{options.out_file}\", \"w\")\n+    env!(options)\n+    puts \"Pre-Syncing groups #{options.groups}\"\n+    groups = options.groups\n+    teams = Team.where(owner_id: nil)\n+    groups.each do |group|\n+      dn = get_group(group)\n+      if teams.select{|t| t.maps_to == dn}.count == 0\n+        if options.create_new_teams\n+          out_file.puts \"TEAM|ADD|#{group}:#{dn}\"\n+          users = get_users_in_group(dn)\n+          members_to_add = []\n+          users.each do |user_name|\n+            user = CloudUser.find_by(login: user_name) rescue nil\n+            if user.nil?\n+              if options.add_new_users\n+                out_file.puts \"USER|ADD|#{user_name}\"\n+                members_to_add.push(user_name)\n+              else\n+                puts \"User: #{user_name} does not exist skipping...\"\n+                next\n+              end\n+            end\n+            members_to_add.push(user_name)\n+          end\n+          out_file.puts \"MEMBER|ADD|#{group}:#{members_to_add.join(\",\")}\"\n+        else\n+          puts \"Could not find team mapping to #{dn}\"\n+          next\n+        end\n+      end\n+    end if groups\n+    teams_to_sync = Team.where(onwer_id: nil).select{|t| t.maps_to}\n+    teams_to_sync.each do |team|\n+      users = get_users_in_group(team.maps_to)\n+      members_to_add = []\n+      users.each do |user_name|\n+        user = CloudUser.find_by(login: user_name) rescue nil\n+        if user.nil?\n+          if options.add_new_users\n+            out_file.puts \"USER|ADD|#{user_name}\"\n+            members_to_add.push(user_name)\n+          else\n+            puts \"User: #{user_name} does not exist skipping...\"\n+            next\n+          end\n+        end\n+        members_to_add.push(user_name)\n+      end\n+      out_file.puts \"MEMBER|ADD|#{team.name}:#{members_to_add.join(\",\")}\"\n+      if options.remove_old_users\n+        members_to_remove = team.members.select(&:explicit_role?).reject {|m| users.include? m.n}\n+        if members_to_remove.count > 0\n+          puts \"Removing members #{members_to_remove.collect {|m| m.n}} from team: #{team.name}\"\n+          out_file.puts \"MEMBER|REMOVE|#{team.name}:#{members_to_remove.collect {|m| m.n}.join(\",\")}\"\n+        end\n+      end\n+    end\n+    0\n+  rescue ArgumentError\n+    warn $!\n+    1\n+  rescue => e\n+    exception e, \"Failed to pre-sync to file #{options.out_file}\"\n+    1\n+  end\n+\n+\n+  def sync(options)\n+    raise ArgumentError, \"Path to config file required. Use --config-file to specify a file\" if options.config_file.nil?\n+    env!(options)\n+    puts \"Syncing groups #{options.groups}\"\n+    groups = options.groups\n+    teams = Team.where(owner_id: nil)\n+    groups.each do |group|\n+      dn = get_group(group)\n+      if teams.select{|t| t.maps_to == dn}.count == 0\n+        if options.create_new_teams\n+          begin\n+            team = validate_and_create_team(group, dn)\n+          rescue OpenShift::UserException => ex\n+            puts \"ERROR: Could not create team: #{ex.message}\"\n+            next\n+          end\n+        else\n+          puts \"ERROR: Could not find team mapping to #{dn}\"\n+          next\n+        end\n+      end\n+    end if groups\n+    teams_to_sync = Team.where(owner_id: nil).select{|t| t.maps_to}\n+    teams_to_sync.each do |team|\n+      users = get_users_in_group(team.maps_to)\n+      if users.count > 0\n+        members_to_add = CloudUser.where(:login.in => users)\n+        if members_to_add and members_to_add.count > 0\n+          puts \"Adding members #{members_to_add.collect{|m| m.login}} to team: #{team.name}\"\n+          team.add_members(members_to_add)\n+        end\n+      end\n+      \n+      if options.remove_old_users\n+        members_to_remove = team.members.select(&:explicit_role?).reject {|m| users.include? m.n}\n+        puts \"Removing members #{members_to_remove.collect {|m| m.n}} from team: #{team.name}\"\n+        team.remove_members(members_to_remove) \n+      end\n+        \n+      new_users = users.reject {|user| team.members.collect{|m| m.n }.include? user}\n+      new_users.each do |user_name|\n+        if options.add_new_users\n+          puts \"Adding new user: #{user_name}\"\n+          user = CloudUser.create(:login => user_name)\n+          team.add_members(user)\n+        else\n+          puts \"ERROR: User with username: #{user_name} does not exist\"\n+          next\n+        end\n+      end\n+      team.save\n+      team.run_jobs\n+    end\n+    0\n+  rescue ArgumentError\n+    warn $!\n+    1\n+  rescue => e\n+    exception e, \"Failed to sync groups #{options.groups}\"\n+    1\n+  end\n+\n+  protected\n+    def env!(options)\n+      require options.broker || PATH\n+      if options.config_file\n+        @ldap_config = YAML.load_file(options.config_file)\n+        @ldap = Net::LDAP.new\n+        @ldap.host = @ldap_config[\"Host\"]\n+        @ldap.port = @ldap_config[\"Port\"]\n+        @ldap.auth @ldap_config[\"Username\"], @ldap_config[\"Password\"]\n+        unless @ldap.bind\n+          puts \"Could not connect to LDAP server #{@ldap.host}\" \n+          exit 1\n+        end\n+      end\n+    end\n+    \n+    def normalize(dn)\n+      return dn.gsub(\",\", \"_\").gsub(\"=\", \"_\")\n+    end\n+    \n+    def validate_and_create_team(name, maps_to=nil)\n+      puts \"Creating team name:#{name}\"\n+      team = Team.new(name: name, maps_to: maps_to)\n+      if team.valid?\n+        team.save_with_duplicate_check!\n+      else\n+        err_msgs = []\n+        team.errors.each do |key, message|\n+          err_msgs.push(message)\n+        end\n+        raise OpenShift::UserException.new(err_msgs.join(\" \"))\n+      end\n+      team  \n+    end\n+    \n+    def get_users_in_group(group_dn)\n+      puts \"Getting users in group: #{group_dn}\"\n+      users = []\n+      base = @ldap_config[\"Get-Users-in-Group\"][\"Base\"]\n+      cn = group_dn[/cn=(.*?),/m, 1]\n+      filter = Net::LDAP::Filter.construct(@ldap_config[\"Get-Users-in-Group\"][\"Filter\"].gsub(\"<group_name>\", cn))\n+      attributes = @ldap_config[\"Get-Users-in-Group\"][\"Attributes\"]\n+      entries = @ldap.search(:base => base, :filter => filter, :attributes => attributes)\n+      if entries.count < 1\n+        puts \"Did not find any users in #{group_dn}\"\n+      else\n+        if entries.count > @ldap_config[\"Max-Number-Of-Members\"]\n+          puts \"Too many users in group: #{group_dn}.  Maximum allowed: #{@ldap_config[\"Max-Number-Of-Members\"]}\"\n+          exit 1\n+        end\n+        entries.each do |entry|\n+          if entry.attribute_names.include? @ldap_config[\"Openshift-Username\"]\n+            users.push(entry[@ldap_config[\"Openshift-Username\"]])\n+          else\n+            values = entry[@ldap_config[\"Get-Users-in-Group\"][\"Attributes\"].first]\n+            if values.count > @ldap_config[\"Max-Number-Of-Members\"]\n+              puts \"Too many users in group: #{group_dn}.  Maximum allowed: #{@ldap_config[\"Max-Number-Of-Members\"]}\"\n+              exit 1\n+            end\n+            values.each do |value|\n+              value = value.split(\"=\")[1] if value.include? \"=\"\n+              users.push(get_user(value))\n+            end\n+          end\n+        end\n+        puts \"Found users: #{users}\"\n+      end\n+      return users\n+    end\n+    \n+    def get_group(group_name)\n+      puts \"Getting group: #{group_name}\"\n+      base = @ldap_config[\"Get-Group\"][\"Base\"]\n+      filter = Net::LDAP::Filter.construct(@ldap_config[\"Get-Group\"][\"Filter\"].gsub(\"<group_name>\", group_name))\n+      attributes = @ldap_config[\"Get-Group\"][\"Attributes\"]\n+      entries = @ldap.search(:base => base, :filter => filter, :attributes => attributes)\n+      raise Exception.new(\"Could not find an entry matching #{group_name}\") if entries.count < 1\n+      raise Exception.new(\"Found more than one entry matching #{group_name}\") if entries.count > 1\n+      entry = entries.first\n+      puts \"Found group dn:#{entry.dn}\"\n+      return entry.dn\n+    end\n+    \n+    def get_user(user_id)\n+      puts \"Getting user: #{user_id}\"\n+      base = @ldap_config[\"Get-User\"][\"Base\"]\n+      filter = Net::LDAP::Filter.construct(@ldap_config[\"Get-User\"][\"Filter\"].gsub(\"<user_id>\", user_id))\n+      attributes = @ldap_config[\"Get-User\"][\"Attributes\"]\n+      entries = @ldap.search(:base => base, :filter => filter, :attributes => attributes)\n+      raise Exception.new(\"Could not find an entry matching #{user_id}\") if entries.count < 1\n+      raise Exception.new(\"Found more than one entry matching #{user_id}\") if entries.count > 1\n+      entry = entries.first\n+      puts \"Found user dn:#{entry.dn}\"\n+      return entry[@ldap_config[\"Openshift-Username\"]].first\n+    end\n+\n+    def warn(*args)\n+      $stderr.puts(*args)\n+    end\n+\n+    def exception(e, *args)\n+      $stderr.puts(*args)\n+      $stderr.puts e.message\n+      $stderr.puts \"  #{e.backtrace.join(\"  \\n\")}\"\n+    end\n+end\n+\n+methods = (Command.instance_methods(false) & Command.new.public_methods).map{ |s| s.to_s.gsub('_', '-')}.sort\n+options = OpenStruct.new\n+p = OptionParser.new do |opts|\n+  opts.banner = \"\n+== Synopsis\n+\n+#{File.basename $0}: Manage teams\n+\n+Commands:\n+  list            - List all teams\n+    \n+  create          - Creates a new team\n+                  Requires --name \n+                  \n+  delete          - Delete team\n+                  Requires --name\n+  \n+  show            - Show team and it's members\n+                  Requires --name\n+\n+  sync            - Syncs with LDAP groups\n+\n+  sync-to-file    - Generates a sync file for review.  No changes are made to the teams and their members.\n+                  Requires -out-file\n+\n+  sync-from-file  - Syncs from file.  See sync-to-file\n+                  Requires --in-file\n+  \n+\n+== Usage: oo-admin-ctl-team -c (#{methods.join('|')})\"\n+\n+  opts.separator ''\n+  opts.on('-c', '--command COMMAND',\n+          methods.map(&:to_s),\n+          [],\n+          \"A command to execute (Required)\") do |command|\n+    options.command = command\n+  end\n+  \n+  opts.on('--broker PATH', \"The path to the broker\",","path":"broker-util/oo-admin-ctl-team","position":439,"original_position":439,"commit_id":"452ac8edcc9c11d5d082b688265012d7a8cf5c49","original_commit_id":"452ac8edcc9c11d5d082b688265012d7a8cf5c49","user":{"login":"lnader","id":209597,"avatar_url":"https://avatars.githubusercontent.com/u/209597?","gravatar_id":"73f299282288c8400daf789e9820d299","url":"https://api.github.com/users/lnader","html_url":"https://github.com/lnader","followers_url":"https://api.github.com/users/lnader/followers","following_url":"https://api.github.com/users/lnader/following{/other_user}","gists_url":"https://api.github.com/users/lnader/gists{/gist_id}","starred_url":"https://api.github.com/users/lnader/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lnader/subscriptions","organizations_url":"https://api.github.com/users/lnader/orgs","repos_url":"https://api.github.com/users/lnader/repos","events_url":"https://api.github.com/users/lnader/events{/privacy}","received_events_url":"https://api.github.com/users/lnader/received_events","type":"User","site_admin":false},"body":"The oo-admin-ctl-cartridge does.  When I asked than which admin script I should use as a template (right now the admin scripts do not follow a style), he mentioned the oo-admin-ctl-cartridge.","created_at":"2014-04-07T17:51:29Z","updated_at":"2014-04-07T17:51:29Z","html_url":"https://github.com/openshift/origin-server/pull/5143#discussion_r11355946","pull_request_url":"https://api.github.com/repos/openshift/origin-server/pulls/5143","_links":{"self":{"href":"https://api.github.com/repos/openshift/origin-server/pulls/comments/11355946"},"html":{"href":"https://github.com/openshift/origin-server/pull/5143#discussion_r11355946"},"pull_request":{"href":"https://api.github.com/repos/openshift/origin-server/pulls/5143"}}}}