{"action":"created","comment":{"url":"https://api.github.com/repos/openshift/origin/pulls/comments/37111651","id":37111651,"diff_hunk":"@@ -0,0 +1,174 @@\n+package syncgroups\n+\n+import (\n+\t\"errors\"\n+\t\"fmt\"\n+\t\"io\"\n+\t\"os\"\n+\n+\t\"github.com/spf13/cobra\"\n+\n+\t\"k8s.io/kubernetes/pkg/util\"\n+\tkerrs \"k8s.io/kubernetes/pkg/util/errors\"\n+\n+\tosclient \"github.com/openshift/origin/pkg/client\"\n+\t\"github.com/openshift/origin/pkg/cmd/util/clientcmd\"\n+\tcmdutil \"k8s.io/kubernetes/pkg/kubectl/cmd/util\"\n+)\n+\n+const (\n+\tSyncGroupsRecommendedName = \"sync-groups\"\n+\n+\tsyncGroupsLong = `\n+Sync OpenShift Groups with records from an external provider.\n+\n+`\n+\tsyncGroupsExamples = `  // Sync all groups from an LDAP server\n+  $ %[1]s ldap-all --sync-config=/path/to/ldap-sync-config.yaml\n+\n+  // Sync specific groups specified in a whitelist file with an LDAP server \n+  $ %[1]s ldap-whitelist /path/to/whitelist.txt --sync-config=/path/to/ldap-sync-config.yaml\n+\n+  // Sync all OpenShift Groups that have already been synced with an LDAP server\n+  $ %[1]s openshift-all --sync-config=/path/to/ldap-sync-config.yaml\n+\n+  // Sync specific OpenShift Groups if they have already been synced with an LDAP server\n+  $ %[1]s openshift groups/group1 groups/group2 groups/group3 --sync-config=/path/to/ldap-sync-config.yaml\n+`\n+)\n+\n+// SyncType describes the source and scope of the sync\n+type SyncType string\n+\n+const (\n+\t// SyncTypeLDAPAll determines that the source of the list of groups to sync is LDAP and all\n+\t// groups will be synced\n+\tSyncTypeLDAPAll SyncType = \"ldap-all\"\n+\t// SyncTypeLDAPWhitelist determines that the source of the list of groups to sync is LDAP and\n+\t// a whitelist of groups will be synced\n+\tSyncTypeLDAPWhitelist SyncType = \"ldap-whitelist\"\n+\t// SyncTypeOpenShiftAll determines that the source of the list of groups to sync is OpenShift\n+\t// and all groups will be synced\n+\tSyncTypeOpenShiftAll SyncType = \"openshift-all\"\n+\t// SyncTypeOpenShift determines that the source of the list of groups to sync is OpenShift and\n+\t// a whitelist of groups will be synced\n+\tSyncTypeOpenShift SyncType = \"openshift\"\n+)\n+\n+type SyncGroupsOptions struct {\n+\t// Type is the type of sync to be run\n+\tType SyncType\n+\n+\t// ConfigSource is the path to the sync config\n+\tConfigSource string\n+\n+\t// WhitelistSource is the path to the whitelist or a list of group names\n+\tWhitelistSources util.StringList\n+\n+\t// GroupsInterface is the interface used to interact with OpenShift Group objects\n+\tGroupInterface osclient.GroupInterface\n+\n+\t// Stderr is the writer to write warnings and errors to\n+\tStderr io.Writer\n+\n+\t// Out is the writer to write output to\n+\tOut io.Writer\n+\n+\t// Quiet controls whether warnings are output\n+\tQuiet bool\n+}\n+\n+func NewSyncGroupsOptions() *SyncGroupsOptions {\n+\treturn &SyncGroupsOptions{\n+\t\tStderr:           os.Stderr,\n+\t\tWhitelistSources: util.StringList{},\n+\t}\n+}\n+\n+func NewCmdSyncGroups(name, fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command {\n+\toptions := NewSyncGroupsOptions()\n+\toptions.Out = out\n+\n+\tcmd := &cobra.Command{\n+\t\tUse:     fmt.Sprintf(\"%s TYPE [WHITELIST] CONFIG-SOURCE\", name),\n+\t\tShort:   \"Sync OpenShift Groups with records from an external provider.\",\n+\t\tLong:    syncGroupsLong,\n+\t\tExample: fmt.Sprintf(syncGroupsExamples, fullName),\n+\t\tRun: func(c *cobra.Command, args []string) {\n+\t\t\tif err := options.Complete(args, f); err != nil {\n+\t\t\t\tcmdutil.CheckErr(cmdutil.UsageError(c, err.Error()))\n+\t\t\t}\n+\n+\t\t\tif err := options.Validate(); err != nil {\n+\t\t\t\tcmdutil.CheckErr(cmdutil.UsageError(c, err.Error()))\n+\t\t\t}\n+\n+\t\t\tsyncer, err := options.CreateSyncer()\n+\t\t\tcmdutil.CheckErr(err)\n+\n+\t\t\terrs := syncer.Sync()\n+\t\t\tcmdutil.CheckErr(kerrs.NewAggregate(errs))\n+\t\t},\n+\t}\n+\n+\tcmd.Flags().BoolVarP(&options.Quiet, \"quiet\", \"q\", options.Quiet, \"Suppress warnings\")\n+\tcmd.Flags().StringVar(&options.ConfigSource, \"sync-config\", \"\", \"The path to the sync config\")\n+\tcmdutil.AddPrinterFlags(cmd)\n+\n+\treturn cmd\n+}\n+\n+func (o *SyncGroupsOptions) Complete(args []string, f *clientcmd.Factory) error {\n+\t// Fill type from args[0]\n+\tif len(args) > 0 {\n+\t\to.Type = SyncType(args[0])\n+\t}\n+\n+\t// Add sources from args[1:...]\n+\tif len(args) > 1 {\n+\t\to.WhitelistSources = append(o.WhitelistSources, args[1:]...)\n+\t}\n+\n+\tif f != nil {\n+\t\tosClient, _, err := f.Clients()\n+\t\tif err != nil {\n+\t\t\treturn err\n+\t\t}\n+\t\to.GroupInterface = osClient.Groups()\n+\t}\n+\n+\treturn nil\n+}\n+\n+func (o *SyncGroupsOptions) Validate() error {\n+\tif len(o.Type) == 0 {\n+\t\treturn errors.New(\"sync type is required\")\n+\t}\n+\tswitch o.Type {\n+\tcase SyncTypeLDAPAll:\n+\tcase SyncTypeLDAPWhitelist:\n+\tcase SyncTypeOpenShiftAll:\n+\tcase SyncTypeOpenShift:\n+\tdefault:\n+\t\treturn fmt.Errorf(\"sync type must be one of the following: %v\", []SyncType{SyncTypeLDAPAll, SyncTypeLDAPWhitelist, SyncTypeOpenShift, SyncTypeOpenShiftAll})\n+\t}\n+\tif len(o.ConfigSource) == 0 {\n+\t\treturn errors.New(\"sync config source is required\")\n+\t}\n+\tif (o.Type == SyncTypeLDAPWhitelist || o.Type == SyncTypeOpenShift) && len(o.WhitelistSources.String()) == 0 {\n+\t\treturn fmt.Errorf(\"a path to a whitelist file or a list of unique group identifiers is required for sync type %s\", o.Type)\n+\t}\n+\treturn nil\n+}\n+\n+func (o *SyncGroupsOptions) CreateSyncer() (GroupSyncer, error) {\n+\t// load config file\n+\t// start building options\n+\t// add:\n+\t// ---groupclient for current context\n+\t// ---groupsyncsource\n+\t// ---groupsyncscope\n+\t// ------if it's not an -all, inject whitelist\n+\t// create syncer\n+\treturn nil, nil","path":"pkg/cmd/experimental/syncgroups/sync-groups.go","position":173,"original_position":173,"commit_id":"374daa6bffbd018893688bb9f9b3274e3a569a2b","original_commit_id":"374daa6bffbd018893688bb9f9b3274e3a569a2b","user":{"login":"deads2k","id":8225098,"avatar_url":"https://avatars.githubusercontent.com/u/8225098?v=3","gravatar_id":"","url":"https://api.github.com/users/deads2k","html_url":"https://github.com/deads2k","followers_url":"https://api.github.com/users/deads2k/followers","following_url":"https://api.github.com/users/deads2k/following{/other_user}","gists_url":"https://api.github.com/users/deads2k/gists{/gist_id}","starred_url":"https://api.github.com/users/deads2k/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/deads2k/subscriptions","organizations_url":"https://api.github.com/users/deads2k/orgs","repos_url":"https://api.github.com/users/deads2k/repos","events_url":"https://api.github.com/users/deads2k/events{/privacy}","received_events_url":"https://api.github.com/users/deads2k/received_events","type":"User","site_admin":false},"body":"Build the syncer right here.  You should be able to take your options, build the intermediate object directly in this method and compose your syncer in place right here.  Completely delete your existing `LDAPSyncCommonConfig` and anythign else I marked up there.","created_at":"2015-08-14T19:38:01Z","updated_at":"2015-08-14T19:38:01Z","html_url":"https://github.com/openshift/origin/pull/3996#discussion_r37111651","pull_request_url":"https://api.github.com/repos/openshift/origin/pulls/3996","_links":{"self":{"href":"https://api.github.com/repos/openshift/origin/pulls/comments/37111651"},"html":{"href":"https://github.com/openshift/origin/pull/3996#discussion_r37111651"},"pull_request":{"href":"https://api.github.com/repos/openshift/origin/pulls/3996"}}},"pull_request":{"url":"https://api.github.com/repos/openshift/origin/pulls/3996","id":41564792,"html_url":"https://github.com/openshift/origin/pull/3996","diff_url":"https://github.com/openshift/origin/pull/3996.diff","patch_url":"https://github.com/openshift/origin/pull/3996.patch","issue_url":"https://api.github.com/repos/openshift/origin/issues/3996","number":3996,"state":"open","locked":false,"title":"[WIP] Added LDAP Group Sync for Single LDAP Schema","user":{"login":"stevekuznetsov","id":7328370,"avatar_url":"https://avatars.githubusercontent.com/u/7328370?v=3","gravatar_id":"","url":"https://api.github.com/users/stevekuznetsov","html_url":"https://github.com/stevekuznetsov","followers_url":"https://api.github.com/users/stevekuznetsov/followers","following_url":"https://api.github.com/users/stevekuznetsov/following{/other_user}","gists_url":"https://api.github.com/users/stevekuznetsov/gists{/gist_id}","starred_url":"https://api.github.com/users/stevekuznetsov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stevekuznetsov/subscriptions","organizations_url":"https://api.github.com/users/stevekuznetsov/orgs","repos_url":"https://api.github.com/users/stevekuznetsov/repos","events_url":"https://api.github.com/users/stevekuznetsov/events{/privacy}","received_events_url":"https://api.github.com/users/stevekuznetsov/received_events","type":"User","site_admin":false},"body":"@deads2k @liggitt \r\n\r\nImplementation in place, testing in place ~~but blocked from running by https://github.com/openshift/openldap/pull/6.~~ Implementation for following schema only:\r\n\r\n1. Groups as first-class LDAP entries with an attribute containing a list of members:\r\n  1. members listed with their DN in the attribute\r\n  * members listed with some other UID in the attribute ","created_at":"2015-08-04T12:38:27Z","updated_at":"2015-08-14T19:38:01Z","closed_at":null,"merged_at":null,"merge_commit_sha":"3a3d787b0bcc1bb4bb6e01acb269cfaf38a3469c","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/openshift/origin/pulls/3996/commits","review_comments_url":"https://api.github.com/repos/openshift/origin/pulls/3996/comments","review_comment_url":"https://api.github.com/repos/openshift/origin/pulls/comments{/number}","comments_url":"https://api.github.com/repos/openshift/origin/issues/3996/comments","statuses_url":"https://api.github.com/repos/openshift/origin/statuses/374daa6bffbd018893688bb9f9b3274e3a569a2b","head":{"label":"stevekuznetsov:skuznets/ldap-group-sync","ref":"skuznets/ldap-group-sync","sha":"374daa6bffbd018893688bb9f9b3274e3a569a2b","user":{"login":"stevekuznetsov","id":7328370,"avatar_url":"https://avatars.githubusercontent.com/u/7328370?v=3","gravatar_id":"","url":"https://api.github.com/users/stevekuznetsov","html_url":"https://github.com/stevekuznetsov","followers_url":"https://api.github.com/users/stevekuznetsov/followers","following_url":"https://api.github.com/users/stevekuznetsov/following{/other_user}","gists_url":"https://api.github.com/users/stevekuznetsov/gists{/gist_id}","starred_url":"https://api.github.com/users/stevekuznetsov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stevekuznetsov/subscriptions","organizations_url":"https://api.github.com/users/stevekuznetsov/orgs","repos_url":"https://api.github.com/users/stevekuznetsov/repos","events_url":"https://api.github.com/users/stevekuznetsov/events{/privacy}","received_events_url":"https://api.github.com/users/stevekuznetsov/received_events","type":"User","site_admin":false},"repo":{"id":35963136,"name":"origin","full_name":"stevekuznetsov/origin","owner":{"login":"stevekuznetsov","id":7328370,"avatar_url":"https://avatars.githubusercontent.com/u/7328370?v=3","gravatar_id":"","url":"https://api.github.com/users/stevekuznetsov","html_url":"https://github.com/stevekuznetsov","followers_url":"https://api.github.com/users/stevekuznetsov/followers","following_url":"https://api.github.com/users/stevekuznetsov/following{/other_user}","gists_url":"https://api.github.com/users/stevekuznetsov/gists{/gist_id}","starred_url":"https://api.github.com/users/stevekuznetsov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stevekuznetsov/subscriptions","organizations_url":"https://api.github.com/users/stevekuznetsov/orgs","repos_url":"https://api.github.com/users/stevekuznetsov/repos","events_url":"https://api.github.com/users/stevekuznetsov/events{/privacy}","received_events_url":"https://api.github.com/users/stevekuznetsov/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/stevekuznetsov/origin","description":"OpenShift 3 - build, deploy, and manage your applications with Docker and Kubernetes","fork":true,"url":"https://api.github.com/repos/stevekuznetsov/origin","forks_url":"https://api.github.com/repos/stevekuznetsov/origin/forks","keys_url":"https://api.github.com/repos/stevekuznetsov/origin/keys{/key_id}","collaborators_url":"https://api.github.com/repos/stevekuznetsov/origin/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/stevekuznetsov/origin/teams","hooks_url":"https://api.github.com/repos/stevekuznetsov/origin/hooks","issue_events_url":"https://api.github.com/repos/stevekuznetsov/origin/issues/events{/number}","events_url":"https://api.github.com/repos/stevekuznetsov/origin/events","assignees_url":"https://api.github.com/repos/stevekuznetsov/origin/assignees{/user}","branches_url":"https://api.github.com/repos/stevekuznetsov/origin/branches{/branch}","tags_url":"https://api.github.com/repos/stevekuznetsov/origin/tags","blobs_url":"https://api.github.com/repos/stevekuznetsov/origin/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/stevekuznetsov/origin/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/stevekuznetsov/origin/git/refs{/sha}","trees_url":"https://api.github.com/repos/stevekuznetsov/origin/git/trees{/sha}","statuses_url":"https://api.github.com/repos/stevekuznetsov/origin/statuses/{sha}","languages_url":"https://api.github.com/repos/stevekuznetsov/origin/languages","stargazers_url":"https://api.github.com/repos/stevekuznetsov/origin/stargazers","contributors_url":"https://api.github.com/repos/stevekuznetsov/origin/contributors","subscribers_url":"https://api.github.com/repos/stevekuznetsov/origin/subscribers","subscription_url":"https://api.github.com/repos/stevekuznetsov/origin/subscription","commits_url":"https://api.github.com/repos/stevekuznetsov/origin/commits{/sha}","git_commits_url":"https://api.github.com/repos/stevekuznetsov/origin/git/commits{/sha}","comments_url":"https://api.github.com/repos/stevekuznetsov/origin/comments{/number}","issue_comment_url":"https://api.github.com/repos/stevekuznetsov/origin/issues/comments{/number}","contents_url":"https://api.github.com/repos/stevekuznetsov/origin/contents/{+path}","compare_url":"https://api.github.com/repos/stevekuznetsov/origin/compare/{base}...{head}","merges_url":"https://api.github.com/repos/stevekuznetsov/origin/merges","archive_url":"https://api.github.com/repos/stevekuznetsov/origin/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/stevekuznetsov/origin/downloads","issues_url":"https://api.github.com/repos/stevekuznetsov/origin/issues{/number}","pulls_url":"https://api.github.com/repos/stevekuznetsov/origin/pulls{/number}","milestones_url":"https://api.github.com/repos/stevekuznetsov/origin/milestones{/number}","notifications_url":"https://api.github.com/repos/stevekuznetsov/origin/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/stevekuznetsov/origin/labels{/name}","releases_url":"https://api.github.com/repos/stevekuznetsov/origin/releases{/id}","created_at":"2015-05-20T17:28:25Z","updated_at":"2015-05-20T17:28:28Z","pushed_at":"2015-08-14T18:14:30Z","git_url":"git://github.com/stevekuznetsov/origin.git","ssh_url":"git@github.com:stevekuznetsov/origin.git","clone_url":"https://github.com/stevekuznetsov/origin.git","svn_url":"https://github.com/stevekuznetsov/origin","homepage":"http://www.openshift.org","size":131041,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"openshift:master","ref":"master","sha":"41f6f7d555f6707ae7da6c09a5b749c2d1a4bd1d","user":{"login":"openshift","id":792337,"avatar_url":"https://avatars.githubusercontent.com/u/792337?v=3","gravatar_id":"","url":"https://api.github.com/users/openshift","html_url":"https://github.com/openshift","followers_url":"https://api.github.com/users/openshift/followers","following_url":"https://api.github.com/users/openshift/following{/other_user}","gists_url":"https://api.github.com/users/openshift/gists{/gist_id}","starred_url":"https://api.github.com/users/openshift/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openshift/subscriptions","organizations_url":"https://api.github.com/users/openshift/orgs","repos_url":"https://api.github.com/users/openshift/repos","events_url":"https://api.github.com/users/openshift/events{/privacy}","received_events_url":"https://api.github.com/users/openshift/received_events","type":"Organization","site_admin":false},"repo":{"id":22442668,"name":"origin","full_name":"openshift/origin","owner":{"login":"openshift","id":792337,"avatar_url":"https://avatars.githubusercontent.com/u/792337?v=3","gravatar_id":"","url":"https://api.github.com/users/openshift","html_url":"https://github.com/openshift","followers_url":"https://api.github.com/users/openshift/followers","following_url":"https://api.github.com/users/openshift/following{/other_user}","gists_url":"https://api.github.com/users/openshift/gists{/gist_id}","starred_url":"https://api.github.com/users/openshift/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openshift/subscriptions","organizations_url":"https://api.github.com/users/openshift/orgs","repos_url":"https://api.github.com/users/openshift/repos","events_url":"https://api.github.com/users/openshift/events{/privacy}","received_events_url":"https://api.github.com/users/openshift/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/openshift/origin","description":"OpenShift 3 - build, deploy, and manage your applications with Docker and Kubernetes","fork":false,"url":"https://api.github.com/repos/openshift/origin","forks_url":"https://api.github.com/repos/openshift/origin/forks","keys_url":"https://api.github.com/repos/openshift/origin/keys{/key_id}","collaborators_url":"https://api.github.com/repos/openshift/origin/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/openshift/origin/teams","hooks_url":"https://api.github.com/repos/openshift/origin/hooks","issue_events_url":"https://api.github.com/repos/openshift/origin/issues/events{/number}","events_url":"https://api.github.com/repos/openshift/origin/events","assignees_url":"https://api.github.com/repos/openshift/origin/assignees{/user}","branches_url":"https://api.github.com/repos/openshift/origin/branches{/branch}","tags_url":"https://api.github.com/repos/openshift/origin/tags","blobs_url":"https://api.github.com/repos/openshift/origin/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/openshift/origin/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/openshift/origin/git/refs{/sha}","trees_url":"https://api.github.com/repos/openshift/origin/git/trees{/sha}","statuses_url":"https://api.github.com/repos/openshift/origin/statuses/{sha}","languages_url":"https://api.github.com/repos/openshift/origin/languages","stargazers_url":"https://api.github.com/repos/openshift/origin/stargazers","contributors_url":"https://api.github.com/repos/openshift/origin/contributors","subscribers_url":"https://api.github.com/repos/openshift/origin/subscribers","subscription_url":"https://api.github.com/repos/openshift/origin/subscription","commits_url":"https://api.github.com/repos/openshift/origin/commits{/sha}","git_commits_url":"https://api.github.com/repos/openshift/origin/git/commits{/sha}","comments_url":"https://api.github.com/repos/openshift/origin/comments{/number}","issue_comment_url":"https://api.github.com/repos/openshift/origin/issues/comments{/number}","contents_url":"https://api.github.com/repos/openshift/origin/contents/{+path}","compare_url":"https://api.github.com/repos/openshift/origin/compare/{base}...{head}","merges_url":"https://api.github.com/repos/openshift/origin/merges","archive_url":"https://api.github.com/repos/openshift/origin/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/openshift/origin/downloads","issues_url":"https://api.github.com/repos/openshift/origin/issues{/number}","pulls_url":"https://api.github.com/repos/openshift/origin/pulls{/number}","milestones_url":"https://api.github.com/repos/openshift/origin/milestones{/number}","notifications_url":"https://api.github.com/repos/openshift/origin/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/openshift/origin/labels{/name}","releases_url":"https://api.github.com/repos/openshift/origin/releases{/id}","created_at":"2014-07-30T20:04:05Z","updated_at":"2015-08-14T18:40:53Z","pushed_at":"2015-08-14T19:36:28Z","git_url":"git://github.com/openshift/origin.git","ssh_url":"git@github.com:openshift/origin.git","clone_url":"https://github.com/openshift/origin.git","svn_url":"https://github.com/openshift/origin","homepage":"http://www.openshift.org","size":226189,"stargazers_count":621,"watchers_count":621,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":348,"mirror_url":null,"open_issues_count":529,"forks":348,"open_issues":529,"watchers":621,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/openshift/origin/pulls/3996"},"html":{"href":"https://github.com/openshift/origin/pull/3996"},"issue":{"href":"https://api.github.com/repos/openshift/origin/issues/3996"},"comments":{"href":"https://api.github.com/repos/openshift/origin/issues/3996/comments"},"review_comments":{"href":"https://api.github.com/repos/openshift/origin/pulls/3996/comments"},"review_comment":{"href":"https://api.github.com/repos/openshift/origin/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/openshift/origin/pulls/3996/commits"},"statuses":{"href":"https://api.github.com/repos/openshift/origin/statuses/374daa6bffbd018893688bb9f9b3274e3a569a2b"}}}}