{"action":"created","comment":{"url":"https://api.github.com/repos/quattor/configuration-modules-core/pulls/comments/40493105","id":40493105,"diff_hunk":"@@ -0,0 +1,810 @@\n+# #\n+# Software subject to following license(s):\n+#   Apache 2 License (http://www.opensource.org/licenses/apache2.0)\n+#   Copyright (c) Responsible Organization\n+#\n+\n+# #\n+# Current developer(s):\n+#   Jindrich Novy <jindrich.novy@morganstanley.com>\n+#\n+\n+# #\n+# Author(s): Jindrich Novy\n+#\n+\n+package NCM::Component::spma::yumng;\n+\n+#\n+# a few standard statements, mandatory for all components\n+#\n+use strict;\n+use warnings;\n+use NCM::Component;\n+our $EC  = LC::Exception::Context->new->will_store_all;\n+our @ISA = qw(NCM::Component);\n+use EDG::WP4::CCM::Element qw(unescape);\n+\n+use CAF::Process;\n+use CAF::FileWriter;\n+use Set::Scalar;\n+use File::Path qw(mkpath rmtree);\n+use LWP::Simple;\n+use Text::Glob qw(match_glob);\n+\n+use constant HOSTNAME            => \"/system/network/hostname\";\n+use constant DOMAINNAME          => \"/system/network/domainname\";\n+use constant REPOS_DIR           => \"/etc/yum.repos.d\";\n+use constant REPOS_TREE          => \"/software/repositories\";\n+use constant PKGS_TREE           => \"/software/packages\";\n+use constant GROUPS_TREE         => \"/software/groups/names\";\n+use constant CMP_TREE            => \"/software/components/spma\";\n+use constant YUM_PACKAGE_LIST    => \"/etc/yum/pluginconf.d/versionlock.list\";\n+use constant YUM_CONF_FILE       => \"/etc/yum.conf\";\n+use constant RPM_QUERY_INSTALLED => qw(rpm -qa --nosignature --nodigest --qf %{EPOCH}:%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\\n);\n+use constant REPO_AVAIL_PKGS     => qw(repoquery -C --show-duplicates --all --qf %{EPOCH}:%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH});\n+use constant YUM_PLUGIN_OPTS\t => \"--disableplugin=\\* --enableplugin=fastestmirror --enableplugin=versionlock\";\n+use constant YUM_TEST_CHROOT     => qw(/tmp/spma_yum_testroot);\n+use constant SPMA                => \"/software/components/spma\";\n+use constant SPMAPROXY           => \"/software/components/spma/proxy\";\n+\n+our $NoActionSupported = 1;\n+\n+# If user packages are not allowed, removes any repositories present\n+# in the system that are not listed in $allowed_repos.\n+sub cleanup_old_repos\n+{\n+    my ( $self, $repo_dir, $allowed_repos, $allow_user_pkgs ) = @_;\n+\n+    return 1 if $allow_user_pkgs;\n+\n+    my $dir;\n+    if ( !opendir( $dir, $repo_dir ) ) {\n+        $self->error(\"Unable to read repositories in $repo_dir\");\n+        return 0;\n+    }\n+\n+    my $current = Set::Scalar->new( map( m{(.*)\\.repo$}, readdir($dir) ) );\n+\n+    closedir($dir);\n+    my $allowed = Set::Scalar->new( map( $_->{name}, @$allowed_repos ) );\n+    my $rm = $current - $allowed;\n+    foreach my $i (@$rm) {\n+        # We use $f here to make Devel::Cover happy\n+        my $f = \"$repo_dir/$i.repo\";\n+        $self->verbose(\"Unlinking outdated repository $f\");\n+        if ( !unlink($f) ) {\n+            $self->error(\"Unable to remove outdated repository $i: $!\");\n+            return 0;\n+        }\n+    }\n+    return 1;\n+}\n+\n+=pod\n+\n+=head2 C<execute_yum_command>\n+\n+Executes C<$command> for reason C<$why>. Optionally with standard\n+input C<$stdin>.  The command may be executed even under --noaction if\n+C<$keeps_state> has a true value.\n+\n+If the command is executed, this method returns its standard output\n+upon success or C<undef> in case of error.  If the command is not\n+executed the method always returns a true value (usually 1, but don't\n+rely on this!).\n+\n+Yum-based commands require annoying error handling: they may exit 0\n+even upon errors.  In those cases, we have to detect errors by looking\n+at stderr.  This method just encapsulates all that logic, keeping the\n+callers clean.\n+\n+=cut\n+\n+my $yum_warned;\n+my $yum_error;\n+\n+sub execute_yum_command\n+{\n+    my ( $self, $command, $why, $keeps_state, $stdin, $error_logger, $error_ok ) = @_;\n+\n+    $error_logger = \"error\" if ( !( $error_logger && $error_logger =~ m/^(error|warn|info|verbose)$/ ) );\n+\n+    $yum_warned = 0;\n+\n+    my ( %opts, $out, $err, @missing );\n+\n+    %opts = ( log => $self,\n+        stdout      => \\$out,\n+        stderr      => \\$err,\n+        keeps_state => $keeps_state );\n+\n+    $opts{stdin} = $stdin if defined($stdin);\n+\n+    my $cmd = CAF::Process->new( $command, %opts );\n+\n+    $cmd->info(\"$why\");\n+    $cmd->execute();\n+    $yum_error = $err;\n+    if ( $err && ( !defined($error_ok) || $error_ok != 1 ) ) {\n+        $self->warn(\"$why produced warnings: $err\") if ( $err && ( !defined($error_ok) || $error_ok != 1 ) );\n+        $yum_warned = 1;\n+    }\n+    $self->verbose(\"$why output:\\n$out\") if ( defined($out) );\n+    if ( $? ||\n+        ( $err && $err =~ m{^(?:Error|Failed|\n+                      (?:Could \\s+ not \\s+ match)|\n+                      (?:Transaction \\s+.*rror)|\n+                      (?:Unknown \\s+ group \\s+  package \\s+ type) |\n+                      (?:.*requested \\s+ URL \\s+ returned \\s+ error))}oxmi ) ||\n+        ( $out && ( @missing = ( $out =~ m{^No package (.*) available}omg ) ) )\n+      ) {\n+        return undef if ( !defined($error_ok) || $error_ok != 1 );\n+        $self->$error_logger( \"Failed $why: \", $err || \"(empty/undef stderr)\" );\n+        if (@missing) {\n+            $self->$error_logger( \"Missing packages: \", join ( \" \", @missing ) );\n+        }\n+        return $err;\n+    }\n+    return $cmd->{NoAction} || $out;\n+}\n+\n+sub execute_yum_command_with_recovery\n+{\n+    my ( $self, $command, $why, $keeps_state, $stdin, $error_logger, $error_ok ) = @_;\n+    my $status = $self->execute_yum_command($command, $why, $keeps_state, $stdin, $error_logger, $error_ok);\n+    my $packages_modified = 0;\n+\n+    if ( !defined($status) ) {\n+\tmy @lines = split /\\n/, $yum_error;\n+\tforeach my $line (@lines) {\n+\t    my $cf = index($line, 'conflicts with file from package');\n+\t    if ( $cf != -1) {\n+\t\tmy $pkg = $line;\n+\t\t$pkg =~ s,^.*package ,,;\n+\t\t$pkg =~ s,-[0-9]*:,-,;\n+\t\t$self->execute_yum_command([\"rpm -e --nodeps $pkg\"], \"removing $pkg to avoid file conflict\");\n+\t\t$packages_modified = 1;\n+\t    }\n+\t}\n+\tif ( $packages_modified ) {\n+\t    $status = $self->execute_yum_command($command, 'retrying: '.$why, $keeps_state, $stdin, $error_logger, $error_ok);\n+\t}\n+    }\n+    return $status;\n+}\n+\n+sub Configure\n+{\n+    my ( $self, $config ) = @_;\n+\n+    # Make sure stdout and stderr is flushed every time to not to\n+    # put mess on serial console\n+    autoflush STDOUT 1;\n+    autoflush STDERR 1;\n+\n+    # We are parsing some outputs in this component. We must set a\n+    # locale that we can understand.\n+    local $ENV{LANG}   = 'C';\n+    local $ENV{LC_ALL} = 'C';\n+\n+    my $repos = $config->getElement(REPOS_TREE)->getTree();\n+    my $t     = $config->getElement(CMP_TREE)->getTree();\n+    \n+    # Display system info\n+    if ( defined($t->{quattor_os_release}) ) {\n+\t$self->info(\"target OS build: \", $t->{quattor_os_release});\n+    }\n+    \n+    my $spmaver = $self->execute_yum_command( [\"rpm -q --qf %{NAME}-%{VERSION}-%{RELEASE}.%{ARCH} ncm-spma\"], \"checking for spma version\", 1);\n+    $self->info(\"SPMA version: \", $spmaver);\n+    $self->info(\"User packages permitted: $t->{userpkgs}\");\n+\n+    # Convert these crappily-defined fields into real Perl booleans.\n+    $t->{run}      = $t->{run} eq 'yes';\n+    $t->{userpkgs} = defined( $t->{userpkgs} ) && $t->{userpkgs} eq 'yes';\n+\n+    # test for sharp spma execution early\n+    my $spma_run = 0;\n+    if ( -e \"/.spma-run\" ) {\n+        if ( !unlink \"/.spma-run\" ) {\n+            $self->warn(\"unable to remove file /.spma-run: $!\");\n+        }\n+\t$spma_run = 1;\n+    }\n+\n+    # Detect legacy OS (RHEL5 and older)\n+    my $legacy_os = 0;\n+    my $fhi;\n+    if ( open( $fhi, '<', \"/etc/redhat-release\" ) ) {\n+        while ( my $line = <$fhi> ) {\n+            if ( index( $line, 'release 5' ) >= 0 ) {\n+                $legacy_os = 1;\n+                last;\n+            }\n+        }\n+        $fhi->close();\n+    } else {\n+        $self->warn(\"Unable to determine OS release.\");\n+    }\n+\n+    # Generate YUM config file\n+    my $yum_conf_file = CAF::FileWriter->new( YUM_CONF_FILE, log => $self );\n+    my $excludes      = $t->{excludes};\n+    print $yum_conf_file $t->{yumconf};\n+    print $yum_conf_file \"exclude=\" . join ( \" \", sort @$excludes );\n+    $yum_conf_file->close();\n+\n+    if ( !$NoAction ) {\n+        # Remove all repositories if userpkgs is not defined\n+        $self->cleanup_old_repos( REPOS_DIR, $repos, $t->{userpkgs} ) or return 0;\n+    }\n+\n+    # Generate new installation repositories from host profile\n+    my $proxy = !defined($t->{proxy}) ? 'yes' : $t->{proxy};\n+    foreach my $repo (@$repos) {\n+        my $fh = CAF::FileWriter->new( REPOS_DIR . \"/spma-$repo->{name}.repo\", log => $self );\n+        my $prots = $repo->{protocols}->[0];\n+        my $url   = $prots->{url};\n+        my $urls;\n+        my $repo_proxy = defined($repo->{proxy}) ? 'yes' : 'no';\n+        my $disable_proxy = defined($repo->{disableproxy}) ? 'yes' : 'no';\n+        if ( $url =~ /http/ && $proxy eq 'yes' && $disable_proxy eq 'no' ) {\n+            if ( $config->elementExists(SPMAPROXY) ) {\n+                my $spma       = $config->getElement(SPMA)->getTree;\n+                my $proxyhost = $spma->{proxyhost};\n+                my $proxyport;\n+                my @proxies    = split /,/, $proxyhost;\n+                if ( $spma->{proxyport} ) {\n+                    $proxyport = $spma->{proxyport};\n+                }\n+                if ($proxyhost) {\n+\t\t    if ( $repo_proxy eq 'no' ) {\n+\t\t\twhile (@proxies) {\n+\t\t\t    my $prx = shift(@proxies);\n+\t\t\t    $prx .= \":$proxyport\" if $spma->{proxyport};\n+\t\t\t    $url =~ s{(https?)://([^/]*)/}{$1://$prx/};\n+\t\t\t    $urls .= $url . ' ';\n+\t\t\t}\n+\t\t    } else {\n+\t\t\t$url .= \":$proxyport\" if $spma->{proxyport};\n+\t\t\t$url =~ s,http?://,,;\n+\t\t\t$url =~ s,[^/]*/,,;\n+\t\t\t$url = $repo->{proxy} . $url;\n+\t\t    }\n+\t\t}\n+\t    }\n+\t}\n+\tif (!defined($urls)) {\n+\t    $urls = $url;\n+\t}\n+        my $repofile = \"[$repo->{name}]\\nname=$repo->{name}\\nbaseurl=$urls\\nenabled=$repo->{enabled}\\ngpgcheck=$repo->{gpgcheck}\\n\";\n+        if ( defined( $repo->{mirrorlist} ) && $repo->{mirrorlist} ) {\n+            $repofile = \"[$repo->{name}]\\nname=$repo->{name}\\nmirrorlist=$url\\nenabled=$repo->{enabled}\\ngpgcheck=$repo->{gpgcheck}\\n\";\n+        }\n+        print $fh \"# File generated by \", __PACKAGE__, \". Do not edit\\n\";\n+        print $fh $repofile;\n+        $fh->close();\n+    }\n+\n+    # Preprocess required packages and separate version-locked\n+    #    - also skip package dualities - e.g. both kernel and kernel-2.6.32-504.1.3.el6.x86_64\n+    #      specified on yum install commandline will skip older version-locked package but\n+    #      will install the latest what is undesired. Simply keep only version-locked variant.\n+    my $pkgs               = $config->getElement(PKGS_TREE)->getTree();\n+    my $wanted_pkgs        = Set::Scalar->new();\n+    my $wanted_pkgs_locked = Set::Scalar->new();\n+    my $found_spma         = 0;\n+    my @pkl;\n+    my @pkl_v;\n+    my @pkl_a;\n+\n+    for my $name ( keys %$pkgs ) {\n+        if ( !$found_spma && substr( unescape $name, 0, 8 ) eq 'ncm-spma' ) {\n+            $found_spma = 1;\n+        }\n+        my $vra = $pkgs->{$name};\n+        while ( my ( $vers, $a ) = each(%$vra) ) {","path":"ncm-spma/src/main/perl/spma/yumng.pm","position":307,"original_position":307,"commit_id":"1e6bcd33951d8e71468e101a80a6ddc552d72456","original_commit_id":"1e6bcd33951d8e71468e101a80a6ddc552d72456","user":{"login":"stdweird","id":1517606,"avatar_url":"https://avatars.githubusercontent.com/u/1517606?v=3","gravatar_id":"","url":"https://api.github.com/users/stdweird","html_url":"https://github.com/stdweird","followers_url":"https://api.github.com/users/stdweird/followers","following_url":"https://api.github.com/users/stdweird/following{/other_user}","gists_url":"https://api.github.com/users/stdweird/gists{/gist_id}","starred_url":"https://api.github.com/users/stdweird/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stdweird/subscriptions","organizations_url":"https://api.github.com/users/stdweird/orgs","repos_url":"https://api.github.com/users/stdweird/repos","events_url":"https://api.github.com/users/stdweird/events{/privacy}","received_events_url":"https://api.github.com/users/stdweird/received_events","type":"User","site_admin":false},"body":"`each` is evil. https://github.com/quattor/CAF/issues/109","created_at":"2015-09-26T12:20:30Z","updated_at":"2015-09-26T12:20:30Z","html_url":"https://github.com/quattor/configuration-modules-core/pull/587#discussion_r40493105","pull_request_url":"https://api.github.com/repos/quattor/configuration-modules-core/pulls/587","_links":{"self":{"href":"https://api.github.com/repos/quattor/configuration-modules-core/pulls/comments/40493105"},"html":{"href":"https://github.com/quattor/configuration-modules-core/pull/587#discussion_r40493105"},"pull_request":{"href":"https://api.github.com/repos/quattor/configuration-modules-core/pulls/587"}}},"pull_request":{"url":"https://api.github.com/repos/quattor/configuration-modules-core/pulls/587","id":46045578,"html_url":"https://github.com/quattor/configuration-modules-core/pull/587","diff_url":"https://github.com/quattor/configuration-modules-core/pull/587.diff","patch_url":"https://github.com/quattor/configuration-modules-core/pull/587.patch","issue_url":"https://api.github.com/repos/quattor/configuration-modules-core/issues/587","number":587,"state":"open","locked":false,"title":"ncm-spma: Next Generation Yum Module [WIP / early review]","user":{"login":"ned21","id":278425,"avatar_url":"https://avatars.githubusercontent.com/u/278425?v=3","gravatar_id":"","url":"https://api.github.com/users/ned21","html_url":"https://github.com/ned21","followers_url":"https://api.github.com/users/ned21/followers","following_url":"https://api.github.com/users/ned21/following{/other_user}","gists_url":"https://api.github.com/users/ned21/gists{/gist_id}","starred_url":"https://api.github.com/users/ned21/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ned21/subscriptions","organizations_url":"https://api.github.com/users/ned21/orgs","repos_url":"https://api.github.com/users/ned21/repos","events_url":"https://api.github.com/users/ned21/events{/privacy}","received_events_url":"https://api.github.com/users/ned21/received_events","type":"User","site_admin":false},"body":"We wanted to publish this code for discussion before next week's workshop. Assistance/guidance on how to produce good unit tests and any other improvements would be much appreciated!\r\n\r\n(Sorry about the merge conflicts, they and the commit history will get cleaned up in due course!)","created_at":"2015-09-25T18:56:13Z","updated_at":"2015-09-26T12:20:30Z","closed_at":null,"merged_at":null,"merge_commit_sha":null,"assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/quattor/configuration-modules-core/pulls/587/commits","review_comments_url":"https://api.github.com/repos/quattor/configuration-modules-core/pulls/587/comments","review_comment_url":"https://api.github.com/repos/quattor/configuration-modules-core/pulls/comments{/number}","comments_url":"https://api.github.com/repos/quattor/configuration-modules-core/issues/587/comments","statuses_url":"https://api.github.com/repos/quattor/configuration-modules-core/statuses/1e6bcd33951d8e71468e101a80a6ddc552d72456","head":{"label":"ned21:yum-ng","ref":"yum-ng","sha":"1e6bcd33951d8e71468e101a80a6ddc552d72456","user":{"login":"ned21","id":278425,"avatar_url":"https://avatars.githubusercontent.com/u/278425?v=3","gravatar_id":"","url":"https://api.github.com/users/ned21","html_url":"https://github.com/ned21","followers_url":"https://api.github.com/users/ned21/followers","following_url":"https://api.github.com/users/ned21/following{/other_user}","gists_url":"https://api.github.com/users/ned21/gists{/gist_id}","starred_url":"https://api.github.com/users/ned21/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ned21/subscriptions","organizations_url":"https://api.github.com/users/ned21/orgs","repos_url":"https://api.github.com/users/ned21/repos","events_url":"https://api.github.com/users/ned21/events{/privacy}","received_events_url":"https://api.github.com/users/ned21/received_events","type":"User","site_admin":false},"repo":{"id":9676040,"name":"configuration-modules-core","full_name":"ned21/configuration-modules-core","owner":{"login":"ned21","id":278425,"avatar_url":"https://avatars.githubusercontent.com/u/278425?v=3","gravatar_id":"","url":"https://api.github.com/users/ned21","html_url":"https://github.com/ned21","followers_url":"https://api.github.com/users/ned21/followers","following_url":"https://api.github.com/users/ned21/following{/other_user}","gists_url":"https://api.github.com/users/ned21/gists{/gist_id}","starred_url":"https://api.github.com/users/ned21/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ned21/subscriptions","organizations_url":"https://api.github.com/users/ned21/orgs","repos_url":"https://api.github.com/users/ned21/repos","events_url":"https://api.github.com/users/ned21/events{/privacy}","received_events_url":"https://api.github.com/users/ned21/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/ned21/configuration-modules-core","description":"Core NCM components for Quattor","fork":true,"url":"https://api.github.com/repos/ned21/configuration-modules-core","forks_url":"https://api.github.com/repos/ned21/configuration-modules-core/forks","keys_url":"https://api.github.com/repos/ned21/configuration-modules-core/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ned21/configuration-modules-core/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ned21/configuration-modules-core/teams","hooks_url":"https://api.github.com/repos/ned21/configuration-modules-core/hooks","issue_events_url":"https://api.github.com/repos/ned21/configuration-modules-core/issues/events{/number}","events_url":"https://api.github.com/repos/ned21/configuration-modules-core/events","assignees_url":"https://api.github.com/repos/ned21/configuration-modules-core/assignees{/user}","branches_url":"https://api.github.com/repos/ned21/configuration-modules-core/branches{/branch}","tags_url":"https://api.github.com/repos/ned21/configuration-modules-core/tags","blobs_url":"https://api.github.com/repos/ned21/configuration-modules-core/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ned21/configuration-modules-core/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ned21/configuration-modules-core/git/refs{/sha}","trees_url":"https://api.github.com/repos/ned21/configuration-modules-core/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ned21/configuration-modules-core/statuses/{sha}","languages_url":"https://api.github.com/repos/ned21/configuration-modules-core/languages","stargazers_url":"https://api.github.com/repos/ned21/configuration-modules-core/stargazers","contributors_url":"https://api.github.com/repos/ned21/configuration-modules-core/contributors","subscribers_url":"https://api.github.com/repos/ned21/configuration-modules-core/subscribers","subscription_url":"https://api.github.com/repos/ned21/configuration-modules-core/subscription","commits_url":"https://api.github.com/repos/ned21/configuration-modules-core/commits{/sha}","git_commits_url":"https://api.github.com/repos/ned21/configuration-modules-core/git/commits{/sha}","comments_url":"https://api.github.com/repos/ned21/configuration-modules-core/comments{/number}","issue_comment_url":"https://api.github.com/repos/ned21/configuration-modules-core/issues/comments{/number}","contents_url":"https://api.github.com/repos/ned21/configuration-modules-core/contents/{+path}","compare_url":"https://api.github.com/repos/ned21/configuration-modules-core/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ned21/configuration-modules-core/merges","archive_url":"https://api.github.com/repos/ned21/configuration-modules-core/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ned21/configuration-modules-core/downloads","issues_url":"https://api.github.com/repos/ned21/configuration-modules-core/issues{/number}","pulls_url":"https://api.github.com/repos/ned21/configuration-modules-core/pulls{/number}","milestones_url":"https://api.github.com/repos/ned21/configuration-modules-core/milestones{/number}","notifications_url":"https://api.github.com/repos/ned21/configuration-modules-core/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ned21/configuration-modules-core/labels{/name}","releases_url":"https://api.github.com/repos/ned21/configuration-modules-core/releases{/id}","created_at":"2013-04-25T16:21:09Z","updated_at":"2015-01-13T10:57:12Z","pushed_at":"2015-09-25T18:51:15Z","git_url":"git://github.com/ned21/configuration-modules-core.git","ssh_url":"git@github.com:ned21/configuration-modules-core.git","clone_url":"https://github.com/ned21/configuration-modules-core.git","svn_url":"https://github.com/ned21/configuration-modules-core","homepage":null,"size":7418,"stargazers_count":0,"watchers_count":0,"language":"Perl","has_issues":false,"has_downloads":true,"has_wiki":true,"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":"quattor:master","ref":"master","sha":"1475129b7b67c1baac555c71feb2d1230b6bda6a","user":{"login":"quattor","id":1557169,"avatar_url":"https://avatars.githubusercontent.com/u/1557169?v=3","gravatar_id":"","url":"https://api.github.com/users/quattor","html_url":"https://github.com/quattor","followers_url":"https://api.github.com/users/quattor/followers","following_url":"https://api.github.com/users/quattor/following{/other_user}","gists_url":"https://api.github.com/users/quattor/gists{/gist_id}","starred_url":"https://api.github.com/users/quattor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/quattor/subscriptions","organizations_url":"https://api.github.com/users/quattor/orgs","repos_url":"https://api.github.com/users/quattor/repos","events_url":"https://api.github.com/users/quattor/events{/privacy}","received_events_url":"https://api.github.com/users/quattor/received_events","type":"Organization","site_admin":false},"repo":{"id":6471233,"name":"configuration-modules-core","full_name":"quattor/configuration-modules-core","owner":{"login":"quattor","id":1557169,"avatar_url":"https://avatars.githubusercontent.com/u/1557169?v=3","gravatar_id":"","url":"https://api.github.com/users/quattor","html_url":"https://github.com/quattor","followers_url":"https://api.github.com/users/quattor/followers","following_url":"https://api.github.com/users/quattor/following{/other_user}","gists_url":"https://api.github.com/users/quattor/gists{/gist_id}","starred_url":"https://api.github.com/users/quattor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/quattor/subscriptions","organizations_url":"https://api.github.com/users/quattor/orgs","repos_url":"https://api.github.com/users/quattor/repos","events_url":"https://api.github.com/users/quattor/events{/privacy}","received_events_url":"https://api.github.com/users/quattor/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/quattor/configuration-modules-core","description":"Node Configuration Manager Components for Everyone","fork":false,"url":"https://api.github.com/repos/quattor/configuration-modules-core","forks_url":"https://api.github.com/repos/quattor/configuration-modules-core/forks","keys_url":"https://api.github.com/repos/quattor/configuration-modules-core/keys{/key_id}","collaborators_url":"https://api.github.com/repos/quattor/configuration-modules-core/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/quattor/configuration-modules-core/teams","hooks_url":"https://api.github.com/repos/quattor/configuration-modules-core/hooks","issue_events_url":"https://api.github.com/repos/quattor/configuration-modules-core/issues/events{/number}","events_url":"https://api.github.com/repos/quattor/configuration-modules-core/events","assignees_url":"https://api.github.com/repos/quattor/configuration-modules-core/assignees{/user}","branches_url":"https://api.github.com/repos/quattor/configuration-modules-core/branches{/branch}","tags_url":"https://api.github.com/repos/quattor/configuration-modules-core/tags","blobs_url":"https://api.github.com/repos/quattor/configuration-modules-core/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/quattor/configuration-modules-core/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/quattor/configuration-modules-core/git/refs{/sha}","trees_url":"https://api.github.com/repos/quattor/configuration-modules-core/git/trees{/sha}","statuses_url":"https://api.github.com/repos/quattor/configuration-modules-core/statuses/{sha}","languages_url":"https://api.github.com/repos/quattor/configuration-modules-core/languages","stargazers_url":"https://api.github.com/repos/quattor/configuration-modules-core/stargazers","contributors_url":"https://api.github.com/repos/quattor/configuration-modules-core/contributors","subscribers_url":"https://api.github.com/repos/quattor/configuration-modules-core/subscribers","subscription_url":"https://api.github.com/repos/quattor/configuration-modules-core/subscription","commits_url":"https://api.github.com/repos/quattor/configuration-modules-core/commits{/sha}","git_commits_url":"https://api.github.com/repos/quattor/configuration-modules-core/git/commits{/sha}","comments_url":"https://api.github.com/repos/quattor/configuration-modules-core/comments{/number}","issue_comment_url":"https://api.github.com/repos/quattor/configuration-modules-core/issues/comments{/number}","contents_url":"https://api.github.com/repos/quattor/configuration-modules-core/contents/{+path}","compare_url":"https://api.github.com/repos/quattor/configuration-modules-core/compare/{base}...{head}","merges_url":"https://api.github.com/repos/quattor/configuration-modules-core/merges","archive_url":"https://api.github.com/repos/quattor/configuration-modules-core/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/quattor/configuration-modules-core/downloads","issues_url":"https://api.github.com/repos/quattor/configuration-modules-core/issues{/number}","pulls_url":"https://api.github.com/repos/quattor/configuration-modules-core/pulls{/number}","milestones_url":"https://api.github.com/repos/quattor/configuration-modules-core/milestones{/number}","notifications_url":"https://api.github.com/repos/quattor/configuration-modules-core/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/quattor/configuration-modules-core/labels{/name}","releases_url":"https://api.github.com/repos/quattor/configuration-modules-core/releases{/id}","created_at":"2012-10-31T09:08:07Z","updated_at":"2015-05-08T20:51:08Z","pushed_at":"2015-09-26T07:25:56Z","git_url":"git://github.com/quattor/configuration-modules-core.git","ssh_url":"git@github.com:quattor/configuration-modules-core.git","clone_url":"https://github.com/quattor/configuration-modules-core.git","svn_url":"https://github.com/quattor/configuration-modules-core","homepage":"www.quattor.org","size":15698,"stargazers_count":7,"watchers_count":7,"language":"Perl","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":29,"mirror_url":null,"open_issues_count":59,"forks":29,"open_issues":59,"watchers":7,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/quattor/configuration-modules-core/pulls/587"},"html":{"href":"https://github.com/quattor/configuration-modules-core/pull/587"},"issue":{"href":"https://api.github.com/repos/quattor/configuration-modules-core/issues/587"},"comments":{"href":"https://api.github.com/repos/quattor/configuration-modules-core/issues/587/comments"},"review_comments":{"href":"https://api.github.com/repos/quattor/configuration-modules-core/pulls/587/comments"},"review_comment":{"href":"https://api.github.com/repos/quattor/configuration-modules-core/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/quattor/configuration-modules-core/pulls/587/commits"},"statuses":{"href":"https://api.github.com/repos/quattor/configuration-modules-core/statuses/1e6bcd33951d8e71468e101a80a6ddc552d72456"}}}}