{"action":"created","comment":{"url":"https://api.github.com/repos/citusdata/citus/pulls/comments/239829975","pull_request_review_id":182721961,"id":239829975,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIzOTgyOTk3NQ==","diff_hunk":"@@ -0,0 +1,444 @@\n+/*-------------------------------------------------------------------------\n+ *\n+ * enable_ssl.c\n+ *    UDF and Utilities for enabling ssl during citus setup\n+ *\n+ * Copyright (c) 2018, Citus Data, Inc.\n+ *\n+ *-------------------------------------------------------------------------\n+ */\n+\n+#include \"postgres.h\"\n+\n+#include \"distributed/connection_management.h\"\n+#include \"distributed/worker_protocol.h\"\n+#include \"libpq/libpq.h\"\n+#include \"miscadmin.h\"\n+#include \"nodes/parsenodes.h\"\n+#include \"postmaster/postmaster.h\"\n+#include \"utils/guc.h\"\n+\n+#ifdef USE_OPENSSL\n+#include \"openssl/dsa.h\"\n+#include \"openssl/err.h\"\n+#include \"openssl/pem.h\"\n+#include \"openssl/rsa.h\"\n+#include \"openssl/ssl.h\"\n+#include \"openssl/x509.h\"\n+#endif\n+\n+\n+#define ENABLE_SSL_QUERY \"ALTER SYSTEM SET ssl TO on;\"\n+#define RESET_CITUS_NODE_CONNINFO \\\n+\t\"ALTER SYSTEM SET citus.node_conninfo TO 'sslmode=prefer';\"\n+\n+#define CITUS_AUTO_SSL_COMMON_NAME \"citus-auto-ssl\"\n+#define X509_SUBJECT_COMMON_NAME \"CN\"\n+\n+\n+/* forward declaration of helper functions */\n+static void GloballyReloadConfig(void);\n+\n+\n+#ifdef USE_SSL\n+\n+/* forward declaration of functions used when compiled with ssl */\n+static void EnsureReleaseOpenSSLResource(MemoryContextCallbackFunction func, void *arg);\n+static bool ShouldUseAutoSSL(void);\n+static bool CreateCertificatesWhenNeeded(void);\n+static EVP_PKEY * GeneratePrivateKey(void);\n+static X509 * CreateCertificate(EVP_PKEY *privateKey);\n+static bool StoreCertificate(EVP_PKEY *privateKey, X509 *certificate);\n+#endif /* USE_SSL */\n+\n+\n+PG_FUNCTION_INFO_V1(citus_setup_ssl);\n+PG_FUNCTION_INFO_V1(citus_check_defaults_for_sslmode);\n+\n+\n+/*\n+ * citus_setup_ssl is called during the first creation of a citus extension. It configures\n+ * postgres to use ssl if not already on. During this process it will create certificates\n+ * if they are not already installed in the configured location.\n+ */\n+Datum\n+citus_setup_ssl(PG_FUNCTION_ARGS)\n+{\n+#ifndef USE_SSL\n+\tereport(WARNING, (errmsg(\"can not setup ssl on postgres that is not compiled with \"\n+\t\t\t\t\t\t\t \"ssl support\")));\n+#else /* USE_SSL */\n+\tif (!EnableSSL && ShouldUseAutoSSL())\n+\t{\n+\t\tNode *enableSSLParseTree = NULL;\n+\n+\t\tereport(LOG, (errmsg(\"citus extension created on postgres without ssl enabled, \"\n+\t\t\t\t\t\t\t \"turning it on during creation of the extension\")));\n+\n+\t\t/* execute the alter system statement to enable ssl on within postgres */\n+\t\tenableSSLParseTree = ParseTreeNode(ENABLE_SSL_QUERY);\n+\t\tAlterSystemSetConfigFile((AlterSystemStmt *) enableSSLParseTree);\n+\n+\t\t/*\n+\t\t * ssl=on requires that a key and certificate are present, since we have\n+\t\t * enabled ssl mode here chances are the user didn't install credentials already.\n+\t\t *\n+\t\t * This function will check if they are available and if not it will generate a\n+\t\t * self singed certificate.\n+\t\t */\n+\t\tCreateCertificatesWhenNeeded();\n+\n+#if PG_VERSION_NUM >= 100000\n+\t\tGloballyReloadConfig();\n+#else /* PG_VERSION_NUM < 100000 */\n+\t\tereport(WARNING, (errmsg(\"restart of postgres required\"),\n+\t\t\t\t\t\t  errdetail(\"citus enables ssl in postgres. Postgres \"\n+\t\t\t\t\t\t\t\t\t\"versions before 10.0 require a restart for changes \"\n+\t\t\t\t\t\t\t\t\t\"to ssl to take effect.\"),\n+\t\t\t\t\t\t  errhint(\"when restarting is not possible disable ssl and \"\n+\t\t\t\t\t\t\t\t  \"change citus.conn_nodeinfo to have sslmode lower \"\n+\t\t\t\t\t\t\t\t  \"then require.\")));\n+#endif\n+\t}\n+#endif /* USE_SSL */\n+\n+\tPG_RETURN_NULL();\n+}\n+\n+\n+/*\n+ * citus_check_defaults_for_sslmode is called in the extension upgrade path when\n+ * users upgrade from a previous version to a version that has ssl enabled by default, and\n+ * only when the changed default value conflicts with the setup of the user.\n+ *\n+ * Once it is determined that the default value for citus.node_conninfo is used verbatim\n+ * with ssl not enabled on the cluster it will reinstate the old default value for\n+ * citus.node_conninfo.\n+ *\n+ * In effect this is to not impose the overhead of ssl on an already existing cluster that\n+ * didn't have it enabled already.\n+ */\n+Datum\n+citus_check_defaults_for_sslmode(PG_FUNCTION_ARGS)\n+{\n+\tbool configChanged = false;\n+\n+\tif (EnableSSL)\n+\t{\n+\t\t/* since ssl is on we do not have to change any sslmode back to prefer */\n+\t\tPG_RETURN_NULL();\n+\t}\n+\n+\tif (strcmp(NodeConninfo, \"sslmode=require\") == 0)\n+\t{\n+\t\tNode *resetCitusNodeConnInfoParseTree = NULL;\n+\n+\t\t/* execute the alter system statement to reset node_conninfo to the old default */\n+\n+\t\tereport(LOG, (errmsg(\"reset citus.node_conninfo to old default value as the new \"\n+\t\t\t\t\t\t\t \"value is incompatible with the current ssl setting\")));\n+\n+\t\tresetCitusNodeConnInfoParseTree = ParseTreeNode(RESET_CITUS_NODE_CONNINFO);\n+\t\tAlterSystemSetConfigFile((AlterSystemStmt *) resetCitusNodeConnInfoParseTree);\n+\t\tconfigChanged = true;\n+\t}\n+\n+\tif (configChanged)\n+\t{\n+\t\tGloballyReloadConfig();\n+\t}\n+\n+\tPG_RETURN_NULL();\n+}\n+\n+\n+/*\n+ * GloballyReloadConfig signals postmaster to reload the configuration as well as\n+ * reloading the configuration in the current backend. By reloading the configuration in\n+ * the current backend the changes will also be reflected in the current transaction.\n+ */\n+static void\n+GloballyReloadConfig()\n+{\n+\tif (kill(PostmasterPid, SIGHUP))\n+\t{\n+\t\tereport(WARNING, (errmsg(\"failed to send signal to postmaster: %m\")));\n+\t}\n+\tProcessConfigFile(PGC_SIGHUP);\n+}\n+\n+\n+#ifdef USE_SSL\n+\n+/*\n+ * EnsureReleaseOpenSSLResource registers the openssl allocated resource to be freed when the\n+ * current memory context is reset.\n+ */\n+static void\n+EnsureReleaseOpenSSLResource(MemoryContextCallbackFunction func, void *arg)\n+{\n+\tMemoryContextCallback *cb = MemoryContextAllocZero(CurrentMemoryContext,\n+\t\t\t\t\t\t\t\t\t\t\t\t\t   sizeof(MemoryContextCallback));\n+\tcb->func = func;\n+\tcb->arg = arg;\n+\tMemoryContextRegisterResetCallback(CurrentMemoryContext, cb);\n+}\n+\n+\n+/*\n+ * ShouldUseAutoSSL checks if citus should enable ssl based on the connection settings it\n+ * uses for outward connections. When the outward connection is configured to require ssl\n+ * it assumes the other nodes in the network have the same setting and therefor it will\n+ * automatically enable ssl during installation.\n+ */\n+static bool\n+ShouldUseAutoSSL(void)\n+{\n+\tconst char *sslmode = NULL;\n+\tsslmode = GetConnParam(\"sslmode\");\n+\n+\tif (strcmp(sslmode, \"require\") == 0)\n+\t{\n+\t\treturn true;\n+\t}\n+\n+\treturn false;\n+}\n+\n+\n+/*\n+ * CreateCertificatesWhenNeeded checks if the certificates exists. When they don't exist\n+ * they will be created. The return value tells whether or not new certificates have been\n+ * created. After this function it is guaranteed that certificates are in place. It is not\n+ * guaranteed they have the right permissions as we will not touch the keys if they exist.\n+ */\n+static bool\n+CreateCertificatesWhenNeeded()\n+{\n+\tEVP_PKEY *privateKey = NULL;\n+\tX509 *certificate = NULL;\n+\tbool certificateWritten = false;\n+\tSSL_CTX *sslContext = NULL;\n+\n+\t/*\n+\t * Since postgres might not have initialized ssl at this point we need to initialize\n+\t * it our self to be able to create a context. This code is less extensive then\n+\t * postgres' initialization but that will happen when postgres reloads its\n+\t * configuration with ssl enabled.\n+\t */\n+#ifdef HAVE_OPENSSL_INIT_SSL\n+\tOPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL);\n+#else\n+\tSSL_library_init();\n+#endif\n+\n+\tsslContext = SSL_CTX_new(SSLv23_method());\n+\tif (!sslContext)\n+\t{\n+\t\treturn false;\n+\t}\n+\tEnsureReleaseOpenSSLResource((MemoryContextCallbackFunction) & SSL_CTX_free,","path":"src/backend/distributed/utils/enable_ssl.c","position":null,"original_position":240,"commit_id":"1de10a49a98d5e23a0e98563280b0f0627b91ef3","original_commit_id":"f9c540f624a9572137545575ddee0fdae9c4e2fe","user":{"login":"thanodnl","id":273145,"node_id":"MDQ6VXNlcjI3MzE0NQ==","avatar_url":"https://avatars2.githubusercontent.com/u/273145?v=4","gravatar_id":"","url":"https://api.github.com/users/thanodnl","html_url":"https://github.com/thanodnl","followers_url":"https://api.github.com/users/thanodnl/followers","following_url":"https://api.github.com/users/thanodnl/following{/other_user}","gists_url":"https://api.github.com/users/thanodnl/gists{/gist_id}","starred_url":"https://api.github.com/users/thanodnl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thanodnl/subscriptions","organizations_url":"https://api.github.com/users/thanodnl/orgs","repos_url":"https://api.github.com/users/thanodnl/repos","events_url":"https://api.github.com/users/thanodnl/events{/privacy}","received_events_url":"https://api.github.com/users/thanodnl/received_events","type":"User","site_admin":false},"body":"fixed this with some parentheses around the `&funcname`","created_at":"2018-12-07T14:43:38Z","updated_at":"2018-12-07T14:43:38Z","html_url":"https://github.com/citusdata/citus/pull/2503#discussion_r239829975","pull_request_url":"https://api.github.com/repos/citusdata/citus/pulls/2503","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/citusdata/citus/pulls/comments/239829975"},"html":{"href":"https://github.com/citusdata/citus/pull/2503#discussion_r239829975"},"pull_request":{"href":"https://api.github.com/repos/citusdata/citus/pulls/2503"}},"in_reply_to_id":239783519},"pull_request":{"url":"https://api.github.com/repos/citusdata/citus/pulls/2503","id":234314615,"node_id":"MDExOlB1bGxSZXF1ZXN0MjM0MzE0NjE1","html_url":"https://github.com/citusdata/citus/pull/2503","diff_url":"https://github.com/citusdata/citus/pull/2503.diff","patch_url":"https://github.com/citusdata/citus/pull/2503.patch","issue_url":"https://api.github.com/repos/citusdata/citus/issues/2503","number":2503,"state":"open","locked":false,"title":"Turn on ssl by default for new installations","user":{"login":"thanodnl","id":273145,"node_id":"MDQ6VXNlcjI3MzE0NQ==","avatar_url":"https://avatars2.githubusercontent.com/u/273145?v=4","gravatar_id":"","url":"https://api.github.com/users/thanodnl","html_url":"https://github.com/thanodnl","followers_url":"https://api.github.com/users/thanodnl/followers","following_url":"https://api.github.com/users/thanodnl/following{/other_user}","gists_url":"https://api.github.com/users/thanodnl/gists{/gist_id}","starred_url":"https://api.github.com/users/thanodnl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/thanodnl/subscriptions","organizations_url":"https://api.github.com/users/thanodnl/orgs","repos_url":"https://api.github.com/users/thanodnl/repos","events_url":"https://api.github.com/users/thanodnl/events{/privacy}","received_events_url":"https://api.github.com/users/thanodnl/received_events","type":"User","site_admin":false},"body":"Description: Turn on ssl by default for new installations of citus\r\n\r\nThis change will change `citus.node_conninfo` from `sslmode=prefer` to `sslmode=require` when citus is compiled against a postgres with ssl compiled in.\r\n\r\nThis impacts new users onboarding to citus as well as existing users upgrading. Both flows will be explained below in detail.\r\n\r\n**New Users**\r\nWhen a user new to citus has postgres installed and no settings changed the new default would make it hard to setup a cluster. Only once a user tries to distribute their first table the coordinator would open a connection to the worker and give an error that the connection could not be opened.\r\n\r\nTo help new users getting started quickly we check if sslmode is set to required, which it will be unless the setting has been changed. If that is the case we check if ssl is enabled. If the user enabled ssl them self we assume they have setup certificates as well and don't do anything. However new users are not required to have enabled ssl them self. If that is the case we will enable ssl for them and generate self signed certificates.\r\n\r\nThe result is that users who do not have changes any of the default settings will now have ssl enabled. If this is on pg10 or pg11 this just works. On pg9.6 the user is required to restart postgres as it can only enable ssl during boot.\r\n\r\n**Existing Users**\r\nExisting users are a bigger challenge and require some discussion here. The biggest problems arise for users that have not changed the defaults for `ssl` and `citus.node_conninfo`. Because we have changed the default value of the latter they will automatically get that new value configured. When ssl is not enabled for the node in their cluster they are not able to connect from the coordinator and the worker.\r\n\r\nCurrently we do not change any of the settings on upgrade, we only run some checks to warn a user when we detect an incompatible configuration. This warning checks if the new default value is set for `citus.node_conninfo`. If that is the case it is crosschecked with their current ssl value. If ssl is set to off and `sslmode=require` is there we give them a warning during upgrade time (During the execution of `ALTER EXTENSION citus UPDATE`).\r\n\r\nI have tried to alter the system setting for SSL from the sql scripts that get executed during the upgrade of the extension. However we are not allowed to change system settings from pl/pgsql functions. Therefore we raise a warning from that function for now.\r\n\r\nAlternatively I will do some research if we could use a UDF with an implementation in C to change the settings. The goal is to set the value for `citus.node_conninfo` back to the previous default value. This to not drastically change performance for users upgrading if they didn't have ssl enabled already.\r\n\r\n**TODO**\r\n - [x] Run benchmarks to understand the impact enabling ssl has on performance\r\n - [x] Investigate the use of a UDF called from the sql scripts to change the value back to its default.","created_at":"2018-11-28T15:17:18Z","updated_at":"2018-12-07T14:43:38Z","closed_at":null,"merged_at":null,"merge_commit_sha":"1daae07ab0637ddcde7b6ff7961633ab8c5baa4f","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/citusdata/citus/pulls/2503/commits","review_comments_url":"https://api.github.com/repos/citusdata/citus/pulls/2503/comments","review_comment_url":"https://api.github.com/repos/citusdata/citus/pulls/comments{/number}","comments_url":"https://api.github.com/repos/citusdata/citus/issues/2503/comments","statuses_url":"https://api.github.com/repos/citusdata/citus/statuses/1de10a49a98d5e23a0e98563280b0f0627b91ef3","head":{"label":"citusdata:feature/ssl-by-default","ref":"feature/ssl-by-default","sha":"1de10a49a98d5e23a0e98563280b0f0627b91ef3","user":{"login":"citusdata","id":2545424,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI1NDU0MjQ=","avatar_url":"https://avatars2.githubusercontent.com/u/2545424?v=4","gravatar_id":"","url":"https://api.github.com/users/citusdata","html_url":"https://github.com/citusdata","followers_url":"https://api.github.com/users/citusdata/followers","following_url":"https://api.github.com/users/citusdata/following{/other_user}","gists_url":"https://api.github.com/users/citusdata/gists{/gist_id}","starred_url":"https://api.github.com/users/citusdata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/citusdata/subscriptions","organizations_url":"https://api.github.com/users/citusdata/orgs","repos_url":"https://api.github.com/users/citusdata/repos","events_url":"https://api.github.com/users/citusdata/events{/privacy}","received_events_url":"https://api.github.com/users/citusdata/received_events","type":"Organization","site_admin":false},"repo":{"id":50874442,"node_id":"MDEwOlJlcG9zaXRvcnk1MDg3NDQ0Mg==","name":"citus","full_name":"citusdata/citus","private":false,"owner":{"login":"citusdata","id":2545424,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI1NDU0MjQ=","avatar_url":"https://avatars2.githubusercontent.com/u/2545424?v=4","gravatar_id":"","url":"https://api.github.com/users/citusdata","html_url":"https://github.com/citusdata","followers_url":"https://api.github.com/users/citusdata/followers","following_url":"https://api.github.com/users/citusdata/following{/other_user}","gists_url":"https://api.github.com/users/citusdata/gists{/gist_id}","starred_url":"https://api.github.com/users/citusdata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/citusdata/subscriptions","organizations_url":"https://api.github.com/users/citusdata/orgs","repos_url":"https://api.github.com/users/citusdata/repos","events_url":"https://api.github.com/users/citusdata/events{/privacy}","received_events_url":"https://api.github.com/users/citusdata/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/citusdata/citus","description":"Scalable PostgreSQL for multi-tenant and real-time analytics workloads","fork":false,"url":"https://api.github.com/repos/citusdata/citus","forks_url":"https://api.github.com/repos/citusdata/citus/forks","keys_url":"https://api.github.com/repos/citusdata/citus/keys{/key_id}","collaborators_url":"https://api.github.com/repos/citusdata/citus/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/citusdata/citus/teams","hooks_url":"https://api.github.com/repos/citusdata/citus/hooks","issue_events_url":"https://api.github.com/repos/citusdata/citus/issues/events{/number}","events_url":"https://api.github.com/repos/citusdata/citus/events","assignees_url":"https://api.github.com/repos/citusdata/citus/assignees{/user}","branches_url":"https://api.github.com/repos/citusdata/citus/branches{/branch}","tags_url":"https://api.github.com/repos/citusdata/citus/tags","blobs_url":"https://api.github.com/repos/citusdata/citus/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/citusdata/citus/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/citusdata/citus/git/refs{/sha}","trees_url":"https://api.github.com/repos/citusdata/citus/git/trees{/sha}","statuses_url":"https://api.github.com/repos/citusdata/citus/statuses/{sha}","languages_url":"https://api.github.com/repos/citusdata/citus/languages","stargazers_url":"https://api.github.com/repos/citusdata/citus/stargazers","contributors_url":"https://api.github.com/repos/citusdata/citus/contributors","subscribers_url":"https://api.github.com/repos/citusdata/citus/subscribers","subscription_url":"https://api.github.com/repos/citusdata/citus/subscription","commits_url":"https://api.github.com/repos/citusdata/citus/commits{/sha}","git_commits_url":"https://api.github.com/repos/citusdata/citus/git/commits{/sha}","comments_url":"https://api.github.com/repos/citusdata/citus/comments{/number}","issue_comment_url":"https://api.github.com/repos/citusdata/citus/issues/comments{/number}","contents_url":"https://api.github.com/repos/citusdata/citus/contents/{+path}","compare_url":"https://api.github.com/repos/citusdata/citus/compare/{base}...{head}","merges_url":"https://api.github.com/repos/citusdata/citus/merges","archive_url":"https://api.github.com/repos/citusdata/citus/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/citusdata/citus/downloads","issues_url":"https://api.github.com/repos/citusdata/citus/issues{/number}","pulls_url":"https://api.github.com/repos/citusdata/citus/pulls{/number}","milestones_url":"https://api.github.com/repos/citusdata/citus/milestones{/number}","notifications_url":"https://api.github.com/repos/citusdata/citus/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/citusdata/citus/labels{/name}","releases_url":"https://api.github.com/repos/citusdata/citus/releases{/id}","deployments_url":"https://api.github.com/repos/citusdata/citus/deployments","created_at":"2016-02-01T21:58:39Z","updated_at":"2018-12-06T15:25:57Z","pushed_at":"2018-12-07T14:34:58Z","git_url":"git://github.com/citusdata/citus.git","ssh_url":"git@github.com:citusdata/citus.git","clone_url":"https://github.com/citusdata/citus.git","svn_url":"https://github.com/citusdata/citus","homepage":"https://www.citusdata.com","size":11997,"stargazers_count":3088,"watchers_count":3088,"language":"C","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":220,"mirror_url":null,"archived":false,"open_issues_count":577,"license":{"key":"agpl-3.0","name":"GNU Affero General Public License v3.0","spdx_id":"AGPL-3.0","url":"https://api.github.com/licenses/agpl-3.0","node_id":"MDc6TGljZW5zZTE="},"forks":220,"open_issues":577,"watchers":3088,"default_branch":"master"}},"base":{"label":"citusdata:master","ref":"master","sha":"298613824eb61767d2692c5b0a2e1947bfd8ef75","user":{"login":"citusdata","id":2545424,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI1NDU0MjQ=","avatar_url":"https://avatars2.githubusercontent.com/u/2545424?v=4","gravatar_id":"","url":"https://api.github.com/users/citusdata","html_url":"https://github.com/citusdata","followers_url":"https://api.github.com/users/citusdata/followers","following_url":"https://api.github.com/users/citusdata/following{/other_user}","gists_url":"https://api.github.com/users/citusdata/gists{/gist_id}","starred_url":"https://api.github.com/users/citusdata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/citusdata/subscriptions","organizations_url":"https://api.github.com/users/citusdata/orgs","repos_url":"https://api.github.com/users/citusdata/repos","events_url":"https://api.github.com/users/citusdata/events{/privacy}","received_events_url":"https://api.github.com/users/citusdata/received_events","type":"Organization","site_admin":false},"repo":{"id":50874442,"node_id":"MDEwOlJlcG9zaXRvcnk1MDg3NDQ0Mg==","name":"citus","full_name":"citusdata/citus","private":false,"owner":{"login":"citusdata","id":2545424,"node_id":"MDEyOk9yZ2FuaXphdGlvbjI1NDU0MjQ=","avatar_url":"https://avatars2.githubusercontent.com/u/2545424?v=4","gravatar_id":"","url":"https://api.github.com/users/citusdata","html_url":"https://github.com/citusdata","followers_url":"https://api.github.com/users/citusdata/followers","following_url":"https://api.github.com/users/citusdata/following{/other_user}","gists_url":"https://api.github.com/users/citusdata/gists{/gist_id}","starred_url":"https://api.github.com/users/citusdata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/citusdata/subscriptions","organizations_url":"https://api.github.com/users/citusdata/orgs","repos_url":"https://api.github.com/users/citusdata/repos","events_url":"https://api.github.com/users/citusdata/events{/privacy}","received_events_url":"https://api.github.com/users/citusdata/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/citusdata/citus","description":"Scalable PostgreSQL for multi-tenant and real-time analytics workloads","fork":false,"url":"https://api.github.com/repos/citusdata/citus","forks_url":"https://api.github.com/repos/citusdata/citus/forks","keys_url":"https://api.github.com/repos/citusdata/citus/keys{/key_id}","collaborators_url":"https://api.github.com/repos/citusdata/citus/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/citusdata/citus/teams","hooks_url":"https://api.github.com/repos/citusdata/citus/hooks","issue_events_url":"https://api.github.com/repos/citusdata/citus/issues/events{/number}","events_url":"https://api.github.com/repos/citusdata/citus/events","assignees_url":"https://api.github.com/repos/citusdata/citus/assignees{/user}","branches_url":"https://api.github.com/repos/citusdata/citus/branches{/branch}","tags_url":"https://api.github.com/repos/citusdata/citus/tags","blobs_url":"https://api.github.com/repos/citusdata/citus/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/citusdata/citus/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/citusdata/citus/git/refs{/sha}","trees_url":"https://api.github.com/repos/citusdata/citus/git/trees{/sha}","statuses_url":"https://api.github.com/repos/citusdata/citus/statuses/{sha}","languages_url":"https://api.github.com/repos/citusdata/citus/languages","stargazers_url":"https://api.github.com/repos/citusdata/citus/stargazers","contributors_url":"https://api.github.com/repos/citusdata/citus/contributors","subscribers_url":"https://api.github.com/repos/citusdata/citus/subscribers","subscription_url":"https://api.github.com/repos/citusdata/citus/subscription","commits_url":"https://api.github.com/repos/citusdata/citus/commits{/sha}","git_commits_url":"https://api.github.com/repos/citusdata/citus/git/commits{/sha}","comments_url":"https://api.github.com/repos/citusdata/citus/comments{/number}","issue_comment_url":"https://api.github.com/repos/citusdata/citus/issues/comments{/number}","contents_url":"https://api.github.com/repos/citusdata/citus/contents/{+path}","compare_url":"https://api.github.com/repos/citusdata/citus/compare/{base}...{head}","merges_url":"https://api.github.com/repos/citusdata/citus/merges","archive_url":"https://api.github.com/repos/citusdata/citus/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/citusdata/citus/downloads","issues_url":"https://api.github.com/repos/citusdata/citus/issues{/number}","pulls_url":"https://api.github.com/repos/citusdata/citus/pulls{/number}","milestones_url":"https://api.github.com/repos/citusdata/citus/milestones{/number}","notifications_url":"https://api.github.com/repos/citusdata/citus/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/citusdata/citus/labels{/name}","releases_url":"https://api.github.com/repos/citusdata/citus/releases{/id}","deployments_url":"https://api.github.com/repos/citusdata/citus/deployments","created_at":"2016-02-01T21:58:39Z","updated_at":"2018-12-06T15:25:57Z","pushed_at":"2018-12-07T14:34:58Z","git_url":"git://github.com/citusdata/citus.git","ssh_url":"git@github.com:citusdata/citus.git","clone_url":"https://github.com/citusdata/citus.git","svn_url":"https://github.com/citusdata/citus","homepage":"https://www.citusdata.com","size":11997,"stargazers_count":3088,"watchers_count":3088,"language":"C","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":220,"mirror_url":null,"archived":false,"open_issues_count":577,"license":{"key":"agpl-3.0","name":"GNU Affero General Public License v3.0","spdx_id":"AGPL-3.0","url":"https://api.github.com/licenses/agpl-3.0","node_id":"MDc6TGljZW5zZTE="},"forks":220,"open_issues":577,"watchers":3088,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/citusdata/citus/pulls/2503"},"html":{"href":"https://github.com/citusdata/citus/pull/2503"},"issue":{"href":"https://api.github.com/repos/citusdata/citus/issues/2503"},"comments":{"href":"https://api.github.com/repos/citusdata/citus/issues/2503/comments"},"review_comments":{"href":"https://api.github.com/repos/citusdata/citus/pulls/2503/comments"},"review_comment":{"href":"https://api.github.com/repos/citusdata/citus/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/citusdata/citus/pulls/2503/commits"},"statuses":{"href":"https://api.github.com/repos/citusdata/citus/statuses/1de10a49a98d5e23a0e98563280b0f0627b91ef3"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"thanodnl"}}