Merge pull request #5100 from nathanielmanistaatgoogle/python-grpc_set_ssl_roots_override_callback

grpc_set_ssl_roots_override_callback for Python.
diff --git a/Makefile b/Makefile
index 16e6b32..d9cc89d 100644
--- a/Makefile
+++ b/Makefile
@@ -361,7 +361,7 @@
 Q = @
 endif
 
-VERSION = 0.13.0.0
+VERSION = 0.14.0-dev
 
 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
 CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
diff --git a/Rakefile b/Rakefile
index 3a30920..f208a24 100755
--- a/Rakefile
+++ b/Rakefile
@@ -3,6 +3,7 @@
 require 'rspec/core/rake_task'
 require 'rubocop/rake_task'
 require 'bundler/gem_tasks'
+require 'fileutils'
 
 load 'tools/distrib/docker_for_windows.rb'
 
@@ -23,7 +24,11 @@
   ext.ext_dir = File.join('src', 'ruby', 'ext', 'grpc')
   ext.lib_dir = File.join('src', 'ruby', 'lib', 'grpc')
   ext.cross_compile = true
-  ext.cross_platform = ['x86-mingw32', 'x64-mingw32']
+  ext.cross_platform = [
+    'x86-mingw32', 'x64-mingw32',
+    'x86_64-linux', 'x86-linux',
+    'universal-darwin'
+  ]
   ext.cross_compiling do |spec|
     spec.files = %w( etc/roots.pem grpc_c.32.ruby grpc_c.64.ruby )
     spec.files += Dir.glob('src/ruby/bin/**/*')
@@ -91,11 +96,18 @@
 
 end
 
-desc 'Build the gem file under rake_compiler_dock'
-task 'gem:windows' do
+desc 'Build the native gem file under rake_compiler_dock'
+task 'gem:native' do
   verbose = ENV['V'] || '0'
 
-  docker_for_windows "bundle && rake cross native gem RUBY_CC_VERSION=2.3.0:2.2.2:2.1.6:2.0.0 V=#{verbose}"
+  if RUBY_PLATFORM =~ /darwin/
+    FileUtils.touch 'grpc_c.32.ruby'
+    FileUtils.touch 'grpc_c.64.ruby'
+    system "rake cross native gem RUBY_CC_VERSION=2.3.0:2.2.2:2.1.5:2.0.0 V=#{verbose}"
+  else
+    Rake::Task['dlls'].execute
+    docker_for_windows "bundle && rake cross native gem RUBY_CC_VERSION=2.3.0:2.2.2:2.1.5:2.0.0 V=#{verbose}"
+  end
 end
 
 # Define dependencies between the suites.
@@ -105,8 +117,6 @@
 task 'suite:server' => 'suite:wrapper'
 task 'suite:pb' => 'suite:server'
 
-task 'gem:windows' => 'dlls'
-
 desc 'Compiles the gRPC extension then runs all the tests'
 task all: ['suite:idiomatic', 'suite:bidi', 'suite:pb', 'suite:server']
 task default: :all
diff --git a/build.yaml b/build.yaml
index b615945..630a494 100644
--- a/build.yaml
+++ b/build.yaml
@@ -2,12 +2,12 @@
 '#2': It is used among other things to generate all of our project files.
 '#3': Please refer to the templates directory for more information.
 settings:
-  '#': The public version number of the library.
-  version:
-    major: 0
-    minor: 13
-    micro: 0
-    build: 0
+  '#1': The public version number of the library.
+  '#2': Master always has a "-dev" suffix
+  '#3': Use "-preN" suffixes to identify pre-release versions
+  '#4': Per-language overrides are possible with (eg) ruby_version tag here
+  '#5': See the expand_version.py for all the quirks here
+  version: 0.14.0-dev
 filegroups:
 - name: census
   public_headers:
diff --git a/examples/node/greeter_client.js b/examples/node/greeter_client.js
index e0b89bd..9b4b0a7 100644
--- a/examples/node/greeter_client.js
+++ b/examples/node/greeter_client.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,7 +33,7 @@
 
 var PROTO_PATH = __dirname + '/helloworld.proto';
 
-var grpc = require('../../');
+var grpc = require('grpc');
 var hello_proto = grpc.load(PROTO_PATH).helloworld;
 
 function main() {
diff --git a/examples/node/greeter_server.js b/examples/node/greeter_server.js
index 3600c8b..2712b3d 100644
--- a/examples/node/greeter_server.js
+++ b/examples/node/greeter_server.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,7 +33,7 @@
 
 var PROTO_PATH = __dirname + '/helloworld.proto';
 
-var grpc = require('../../');
+var grpc = require('grpc');
 var hello_proto = grpc.load(PROTO_PATH).helloworld;
 
 /**
diff --git a/examples/node/package.json b/examples/node/package.json
new file mode 100644
index 0000000..65c5789
--- /dev/null
+++ b/examples/node/package.json
@@ -0,0 +1,7 @@
+{
+  "name": "grpc-examples",
+  "version": "0.1.0",
+  "dependencies": {
+    "grpc": "0.12.0"
+  }
+}
diff --git a/examples/node/route_guide/route_guide_client.js b/examples/node/route_guide/route_guide_client.js
index edeca6f..e38a21f 100644
--- a/examples/node/route_guide/route_guide_client.js
+++ b/examples/node/route_guide/route_guide_client.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,13 +30,13 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
- 
+
 var async = require('async');
 var fs = require('fs');
 var parseArgs = require('minimist');
 var path = require('path');
 var _ = require('lodash');
-var grpc = require('../../../');
+var grpc = require('grpc');
 var routeguide = grpc.load(__dirname + '/route_guide.proto').routeguide;
 var client = new routeguide.RouteGuide('localhost:50051',
                                        grpc.Credentials.createInsecure());
diff --git a/examples/node/route_guide/route_guide_server.js b/examples/node/route_guide/route_guide_server.js
index 2090a6a..06cf292 100644
--- a/examples/node/route_guide/route_guide_server.js
+++ b/examples/node/route_guide/route_guide_server.js
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,12 +30,12 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
- 
+
 var fs = require('fs');
 var parseArgs = require('minimist');
 var path = require('path');
 var _ = require('lodash');
-var grpc = require('../../../');
+var grpc = require('grpc');
 var routeguide = grpc.load(__dirname + '/route_guide.proto').routeguide;
 
 var COORD_FACTOR = 1e7;
diff --git a/examples/objective-c/helloworld/main.m b/examples/objective-c/helloworld/main.m
index a62f836..bf35799 100644
--- a/examples/objective-c/helloworld/main.m
+++ b/examples/objective-c/helloworld/main.m
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,7 @@
 #import <UIKit/UIKit.h>
 #import "AppDelegate.h"
 
+#import <GRPCClient/GRPCCall+ChannelArg.h>
 #import <GRPCClient/GRPCCall+Tests.h>
 #import <HelloWorld/Helloworld.pbrpc.h>
 
@@ -42,6 +43,7 @@
 int main(int argc, char * argv[]) {
   @autoreleasepool {
     [GRPCCall useInsecureConnectionsForHost:kHostAddress];
+    [GRPCCall setUserAgentPrefix:@"HelloWorld/1.0" forHost:kHostAddress];
 
     HLWGreeter *client = [[HLWGreeter alloc] initWithHost:kHostAddress];
 
diff --git a/grpc.gemspec b/grpc.gemspec
index e305ea5..e990948 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -14,7 +14,6 @@
   s.license       = 'BSD-3-Clause'
 
   s.required_ruby_version = '>= 2.0.0'
-  s.requirements << 'libgrpc ~> 0.11.0 needs to be installed'
 
   s.files = %w( Makefile )
   s.files += %w( etc/roots.pem )
diff --git a/include/grpc++/impl/codegen/async_unary_call.h b/include/grpc++/impl/codegen/async_unary_call.h
index 481b20b..f3c75dc 100644
--- a/include/grpc++/impl/codegen/async_unary_call.h
+++ b/include/grpc++/impl/codegen/async_unary_call.h
@@ -62,40 +62,50 @@
   ClientAsyncResponseReader(ChannelInterface* channel, CompletionQueue* cq,
                             const RpcMethod& method, ClientContext* context,
                             const W& request)
-      : context_(context), call_(channel->CreateCall(method, context, cq)) {
-    init_buf_.SendInitialMetadata(context->send_initial_metadata_);
+      : context_(context),
+        call_(channel->CreateCall(method, context, cq)),
+        collection_(new CallOpSetCollection) {
+    collection_->init_buf_.SetCollection(collection_);
+    collection_->init_buf_.SendInitialMetadata(context->send_initial_metadata_);
     // TODO(ctiller): don't assert
-    GPR_ASSERT(init_buf_.SendMessage(request).ok());
-    init_buf_.ClientSendClose();
-    call_.PerformOps(&init_buf_);
+    GPR_ASSERT(collection_->init_buf_.SendMessage(request).ok());
+    collection_->init_buf_.ClientSendClose();
+    call_.PerformOps(&collection_->init_buf_);
   }
 
   void ReadInitialMetadata(void* tag) {
     GPR_ASSERT(!context_->initial_metadata_received_);
 
-    meta_buf_.set_output_tag(tag);
-    meta_buf_.RecvInitialMetadata(context_);
-    call_.PerformOps(&meta_buf_);
+    collection_->meta_buf_.SetCollection(collection_);
+    collection_->meta_buf_.set_output_tag(tag);
+    collection_->meta_buf_.RecvInitialMetadata(context_);
+    call_.PerformOps(&collection_->meta_buf_);
   }
 
   void Finish(R* msg, Status* status, void* tag) {
-    finish_buf_.set_output_tag(tag);
+    collection_->finish_buf_.SetCollection(collection_);
+    collection_->finish_buf_.set_output_tag(tag);
     if (!context_->initial_metadata_received_) {
-      finish_buf_.RecvInitialMetadata(context_);
+      collection_->finish_buf_.RecvInitialMetadata(context_);
     }
-    finish_buf_.RecvMessage(msg);
-    finish_buf_.ClientRecvStatus(context_, status);
-    call_.PerformOps(&finish_buf_);
+    collection_->finish_buf_.RecvMessage(msg);
+    collection_->finish_buf_.ClientRecvStatus(context_, status);
+    call_.PerformOps(&collection_->finish_buf_);
   }
 
  private:
   ClientContext* context_;
   Call call_;
-  SneakyCallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
-                  CallOpClientSendClose> init_buf_;
-  CallOpSet<CallOpRecvInitialMetadata> meta_buf_;
-  CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>,
-            CallOpClientRecvStatus> finish_buf_;
+
+  class CallOpSetCollection : public CallOpSetCollectionInterface {
+   public:
+    SneakyCallOpSet<CallOpSendInitialMetadata, CallOpSendMessage,
+                    CallOpClientSendClose> init_buf_;
+    CallOpSet<CallOpRecvInitialMetadata> meta_buf_;
+    CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>,
+              CallOpClientRecvStatus> finish_buf_;
+  };
+  std::shared_ptr<CallOpSetCollection> collection_;
 };
 
 template <class W>
diff --git a/include/grpc++/impl/codegen/call.h b/include/grpc++/impl/codegen/call.h
index 1e06768..e65349d 100644
--- a/include/grpc++/impl/codegen/call.h
+++ b/include/grpc++/impl/codegen/call.h
@@ -472,6 +472,17 @@
   size_t status_details_capacity_;
 };
 
+/// An abstract collection of CallOpSet's, to be used whenever
+/// CallOpSet objects must be thought of as a group. Each member
+/// of the group should have a shared_ptr back to the collection,
+/// as will the object that instantiates the collection, allowing
+/// for automatic ref-counting. In practice, any actual use should
+/// derive from this base class. This is specifically necessary if
+/// some of the CallOpSet's in the collection are "Sneaky" and don't
+/// report back to the C++ layer CQ operations
+class CallOpSetCollectionInterface
+    : public std::enable_shared_from_this<CallOpSetCollectionInterface> {};
+
 /// An abstract collection of call ops, used to generate the
 /// grpc_call_op structure to pass down to the lower layers,
 /// and as it is-a CompletionQueueTag, also massages the final
@@ -488,8 +499,14 @@
     max_message_size_ = max_message_size;
   }
 
+  /// Mark this as belonging to a collection if needed
+  void SetCollection(std::shared_ptr<CallOpSetCollectionInterface> collection) {
+    collection_ = collection;
+  }
+
  protected:
   int max_message_size_;
+  std::shared_ptr<CallOpSetCollectionInterface> collection_;
 };
 
 /// Primary implementaiton of CallOpSetInterface.
@@ -527,6 +544,7 @@
     this->Op5::FinishOp(status, max_message_size_);
     this->Op6::FinishOp(status, max_message_size_);
     *tag = return_tag_;
+    collection_.reset();  // drop the ref at this point
     return true;
   }
 
diff --git a/include/grpc++/security/credentials.h b/include/grpc++/security/credentials.h
index 4d64b5e..e0806c0 100644
--- a/include/grpc++/security/credentials.h
+++ b/include/grpc++/security/credentials.h
@@ -83,7 +83,7 @@
 /// authenticate with a server for a given call on a channel.
 ///
 /// \see http://www.grpc.io/docs/guides/auth.html
-class CallCredentials {
+class CallCredentials : private GrpcLibrary {
  public:
   CallCredentials();
   ~CallCredentials();
diff --git a/include/grpc/impl/codegen/compression_types.h b/include/grpc/impl/codegen/compression_types.h
index 94a10da..0daccd9 100644
--- a/include/grpc/impl/codegen/compression_types.h
+++ b/include/grpc/impl/codegen/compression_types.h
@@ -34,7 +34,7 @@
 #ifndef GRPC_IMPL_CODEGEN_COMPRESSION_TYPES_H
 #define GRPC_IMPL_CODEGEN_COMPRESSION_TYPES_H
 
-#include <grpc/support/port_platform.h>
+#include <grpc/impl/codegen/port_platform.h>
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/include/grpc/impl/codegen/propagation_bits.h b/include/grpc/impl/codegen/propagation_bits.h
index d036415..cdd6997 100644
--- a/include/grpc/impl/codegen/propagation_bits.h
+++ b/include/grpc/impl/codegen/propagation_bits.h
@@ -34,7 +34,7 @@
 #ifndef GRPC_IMPL_CODEGEN_H
 #define GRPC_IMPL_CODEGEN_H
 
-#include <grpc/support/port_platform.h>
+#include <grpc/impl/codegen/port_platform.h>
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/include/grpc/impl/codegen/sync.h b/include/grpc/impl/codegen/sync.h
index 7086b5d..04ff0dc 100644
--- a/include/grpc/impl/codegen/sync.h
+++ b/include/grpc/impl/codegen/sync.h
@@ -115,7 +115,8 @@
 /* Atomically release *mu and wait on *cv.  When the calling thread is woken
    from *cv or the deadline abs_deadline is exceeded, execute gpr_mu_lock(mu)
    and return whether the deadline was exceeded.  Use
-   abs_deadline==gpr_inf_future for no deadline.  May return even when not
+   abs_deadline==gpr_inf_future for no deadline.  abs_deadline can be either
+   an absolute deadline, or a GPR_TIMESPAN.  May return even when not
    woken explicitly.  Requires:  *mu and *cv initialized; the calling thread
    holds an exclusive lock on *mu.  */
 GPR_API int gpr_cv_wait(gpr_cv *cv, gpr_mu *mu, gpr_timespec abs_deadline);
diff --git a/include/grpc/impl/codegen/time.h b/include/grpc/impl/codegen/time.h
index b40c2b2..4ed1c3c 100644
--- a/include/grpc/impl/codegen/time.h
+++ b/include/grpc/impl/codegen/time.h
@@ -102,14 +102,16 @@
 GPR_API gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b);
 GPR_API gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b);
 
-/* Return a timespec representing a given number of time units. LONG_MIN is
-   interpreted as gpr_inf_past, and LONG_MAX as gpr_inf_future.  */
-GPR_API gpr_timespec gpr_time_from_micros(long x, gpr_clock_type clock_type);
-GPR_API gpr_timespec gpr_time_from_nanos(long x, gpr_clock_type clock_type);
-GPR_API gpr_timespec gpr_time_from_millis(long x, gpr_clock_type clock_type);
-GPR_API gpr_timespec gpr_time_from_seconds(long x, gpr_clock_type clock_type);
-GPR_API gpr_timespec gpr_time_from_minutes(long x, gpr_clock_type clock_type);
-GPR_API gpr_timespec gpr_time_from_hours(long x, gpr_clock_type clock_type);
+/* Return a timespec representing a given number of time units. INT64_MIN is
+   interpreted as gpr_inf_past, and INT64_MAX as gpr_inf_future.  */
+GPR_API gpr_timespec gpr_time_from_micros(int64_t x, gpr_clock_type clock_type);
+GPR_API gpr_timespec gpr_time_from_nanos(int64_t x, gpr_clock_type clock_type);
+GPR_API gpr_timespec gpr_time_from_millis(int64_t x, gpr_clock_type clock_type);
+GPR_API gpr_timespec
+gpr_time_from_seconds(int64_t x, gpr_clock_type clock_type);
+GPR_API gpr_timespec
+gpr_time_from_minutes(int64_t x, gpr_clock_type clock_type);
+GPR_API gpr_timespec gpr_time_from_hours(int64_t x, gpr_clock_type clock_type);
 
 GPR_API int32_t gpr_time_to_millis(gpr_timespec timespec);
 
diff --git a/package.json b/package.json
index 59e1812..9a86f4d 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "grpc",
-  "version": "0.12.0",
+  "version": "0.14.0-dev",
   "author": "Google Inc.",
   "description": "gRPC Library for Node",
   "homepage": "http://www.grpc.io/",
diff --git a/setup.py b/setup.py
index 9e1559e..ceca6f6 100644
--- a/setup.py
+++ b/setup.py
@@ -54,6 +54,7 @@
 # Break import-style to ensure we can actually find our in-repo dependencies.
 import commands
 import grpc_core_dependencies
+import grpc_version
 
 LICENSE = '3-clause BSD'
 
@@ -118,6 +119,8 @@
           sources=[module_file] + extra_sources,
           include_dirs=include_dirs, libraries=libraries,
           define_macros=define_macros,
+          extra_compile_args=list(CFLAGS),
+          extra_link_args=list(LDFLAGS),
       ) for (module_name, module_file) in zip(module_names, module_files)
   ]
   if build_with_cython:
@@ -214,7 +217,7 @@
 
 setuptools.setup(
     name='grpcio',
-    version='0.12.0b8',
+    version=grpc_version.VERSION,
     license=LICENSE,
     ext_modules=CYTHON_EXTENSION_MODULES,
     packages=list(PACKAGES),
diff --git a/src/core/iomgr/iocp_windows.c b/src/core/iomgr/iocp_windows.c
index 96b6f81..759340e 100644
--- a/src/core/iomgr/iocp_windows.c
+++ b/src/core/iomgr/iocp_windows.c
@@ -57,7 +57,7 @@
 static DWORD deadline_to_millis_timeout(gpr_timespec deadline,
                                         gpr_timespec now) {
   gpr_timespec timeout;
-  static const int max_spin_polling_us = 10;
+  static const int64_t max_spin_polling_us = 10;
   if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
     return INFINITE;
   }
diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c
index a8e2e22..19ee665 100644
--- a/src/core/iomgr/pollset_posix.c
+++ b/src/core/iomgr/pollset_posix.c
@@ -393,7 +393,7 @@
 int grpc_poll_deadline_to_millis_timeout(gpr_timespec deadline,
                                          gpr_timespec now) {
   gpr_timespec timeout;
-  static const int max_spin_polling_us = 10;
+  static const int64_t max_spin_polling_us = 10;
   if (gpr_time_cmp(deadline, gpr_inf_future(deadline.clock_type)) == 0) {
     return -1;
   }
diff --git a/src/core/iomgr/tcp_server.h b/src/core/iomgr/tcp_server.h
index 8f3184f..a39dd3b 100644
--- a/src/core/iomgr/tcp_server.h
+++ b/src/core/iomgr/tcp_server.h
@@ -40,15 +40,14 @@
 /* Forward decl of grpc_tcp_server */
 typedef struct grpc_tcp_server grpc_tcp_server;
 
-typedef struct grpc_tcp_server_acceptor grpc_tcp_server_acceptor;
-struct grpc_tcp_server_acceptor {
+typedef struct grpc_tcp_server_acceptor {
   /* grpc_tcp_server_cb functions share a ref on from_server that is valid
      until the function returns. */
   grpc_tcp_server *from_server;
   /* Indices that may be passed to grpc_tcp_server_port_fd(). */
   unsigned port_index;
   unsigned fd_index;
-};
+} grpc_tcp_server_acceptor;
 
 /* Called for newly connected TCP connections. */
 typedef void (*grpc_tcp_server_cb)(grpc_exec_ctx *exec_ctx, void *arg,
@@ -57,7 +56,7 @@
 
 /* Create a server, initially not bound to any ports. The caller owns one ref.
    If shutdown_complete is not NULL, it will be used by
-   grpc_tcp_server_unref(). */
+   grpc_tcp_server_unref() when the ref count reaches zero. */
 grpc_tcp_server *grpc_tcp_server_create(grpc_closure *shutdown_complete);
 
 /* Start listening to bound ports */
@@ -84,7 +83,7 @@
 /* Returns the file descriptor of the Mth (fd_index) listening socket of the Nth
    (port_index) call to add_port() on this server, or -1 if the indices are out
    of bounds. The file descriptor remains owned by the server, and will be
-   cleaned up when grpc_tcp_server_destroy is called. */
+   cleaned up when the ref count reaches zero. */
 int grpc_tcp_server_port_fd(grpc_tcp_server *s, unsigned port_index,
                             unsigned fd_index);
 
@@ -97,7 +96,7 @@
 void grpc_tcp_server_shutdown_starting_add(grpc_tcp_server *s,
                                            grpc_closure *shutdown_starting);
 
-/* If the recount drops to zero, delete s, and call (exec_ctx==NULL) or enqueue
+/* If the refcount drops to zero, delete s, and call (exec_ctx==NULL) or enqueue
    a call (exec_ctx!=NULL) to shutdown_complete. */
 void grpc_tcp_server_unref(grpc_exec_ctx *exec_ctx, grpc_tcp_server *s);
 
diff --git a/src/core/support/stack_lockfree.c b/src/core/support/stack_lockfree.c
index 2c97ee1..9daecd2 100644
--- a/src/core/support/stack_lockfree.c
+++ b/src/core/support/stack_lockfree.c
@@ -99,7 +99,7 @@
 
   /* Point the head at reserved dummy entry */
   stack->head.contents.index = INVALID_ENTRY_INDEX;
-  /* Fill in the pad and aba_ctr to avoid confusing memcheck tools */
+/* Fill in the pad and aba_ctr to avoid confusing memcheck tools */
 #ifdef GPR_ARCH_64
   stack->head.contents.pad = 0;
 #endif
diff --git a/src/core/support/sync_win32.c b/src/core/support/sync_win32.c
index 84d412a..41998eb 100644
--- a/src/core/support/sync_win32.c
+++ b/src/core/support/sync_win32.c
@@ -87,6 +87,7 @@
       0) {
     SleepConditionVariableCS(cv, &mu->cs, INFINITE);
   } else {
+    abs_deadline = gpr_convert_clock_type(abs_deadline, GPR_CLOCK_REALTIME);
     gpr_timespec now = gpr_now(abs_deadline.clock_type);
     int64_t now_ms = (int64_t)now.tv_sec * 1000 + now.tv_nsec / 1000000;
     int64_t deadline_ms =
diff --git a/src/core/support/time.c b/src/core/support/time.c
index ac8c3bc..423d12f 100644
--- a/src/core/support/time.c
+++ b/src/core/support/time.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -83,12 +83,12 @@
 /* TODO(ctiller): consider merging _nanos, _micros, _millis into a single
    function for maintainability. Similarly for _seconds, _minutes, and _hours */
 
-gpr_timespec gpr_time_from_nanos(long ns, gpr_clock_type type) {
+gpr_timespec gpr_time_from_nanos(int64_t ns, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (ns == LONG_MAX) {
+  if (ns == INT64_MAX) {
     result = gpr_inf_future(type);
-  } else if (ns == LONG_MIN) {
+  } else if (ns == INT64_MIN) {
     result = gpr_inf_past(type);
   } else if (ns >= 0) {
     result.tv_sec = ns / GPR_NS_PER_SEC;
@@ -101,12 +101,12 @@
   return result;
 }
 
-gpr_timespec gpr_time_from_micros(long us, gpr_clock_type type) {
+gpr_timespec gpr_time_from_micros(int64_t us, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (us == LONG_MAX) {
+  if (us == INT64_MAX) {
     result = gpr_inf_future(type);
-  } else if (us == LONG_MIN) {
+  } else if (us == INT64_MIN) {
     result = gpr_inf_past(type);
   } else if (us >= 0) {
     result.tv_sec = us / 1000000;
@@ -119,12 +119,12 @@
   return result;
 }
 
-gpr_timespec gpr_time_from_millis(long ms, gpr_clock_type type) {
+gpr_timespec gpr_time_from_millis(int64_t ms, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (ms == LONG_MAX) {
+  if (ms == INT64_MAX) {
     result = gpr_inf_future(type);
-  } else if (ms == LONG_MIN) {
+  } else if (ms == INT64_MIN) {
     result = gpr_inf_past(type);
   } else if (ms >= 0) {
     result.tv_sec = ms / 1000;
@@ -137,12 +137,12 @@
   return result;
 }
 
-gpr_timespec gpr_time_from_seconds(long s, gpr_clock_type type) {
+gpr_timespec gpr_time_from_seconds(int64_t s, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (s == LONG_MAX) {
+  if (s == INT64_MAX) {
     result = gpr_inf_future(type);
-  } else if (s == LONG_MIN) {
+  } else if (s == INT64_MIN) {
     result = gpr_inf_past(type);
   } else {
     result.tv_sec = s;
@@ -151,12 +151,12 @@
   return result;
 }
 
-gpr_timespec gpr_time_from_minutes(long m, gpr_clock_type type) {
+gpr_timespec gpr_time_from_minutes(int64_t m, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (m >= LONG_MAX / 60) {
+  if (m >= INT64_MAX / 60) {
     result = gpr_inf_future(type);
-  } else if (m <= LONG_MIN / 60) {
+  } else if (m <= INT64_MIN / 60) {
     result = gpr_inf_past(type);
   } else {
     result.tv_sec = m * 60;
@@ -165,12 +165,12 @@
   return result;
 }
 
-gpr_timespec gpr_time_from_hours(long h, gpr_clock_type type) {
+gpr_timespec gpr_time_from_hours(int64_t h, gpr_clock_type type) {
   gpr_timespec result;
   result.clock_type = type;
-  if (h >= LONG_MAX / 3600) {
+  if (h >= INT64_MAX / 3600) {
     result = gpr_inf_future(type);
-  } else if (h <= LONG_MIN / 3600) {
+  } else if (h <= INT64_MIN / 3600) {
     result = gpr_inf_past(type);
   } else {
     result.tv_sec = h * 3600;
diff --git a/src/core/surface/version.c b/src/core/surface/version.c
index 262a13f..7723f39 100644
--- a/src/core/surface/version.c
+++ b/src/core/surface/version.c
@@ -36,4 +36,4 @@
 
 #include <grpc/grpc.h>
 
-const char *grpc_version_string(void) { return "0.13.0.0"; }
+const char *grpc_version_string(void) { return "0.14.0-dev"; }
diff --git a/src/core/transport/chttp2/writing.c b/src/core/transport/chttp2/writing.c
index 095883c..cafecf1 100644
--- a/src/core/transport/chttp2/writing.c
+++ b/src/core/transport/chttp2/writing.c
@@ -75,6 +75,9 @@
 
   GRPC_CHTTP2_FLOW_MOVE_TRANSPORT("write", transport_writing, outgoing_window,
                                   transport_global, outgoing_window);
+  bool is_window_available = transport_writing->outgoing_window > 0;
+  grpc_chttp2_list_flush_writing_stalled_by_transport(transport_writing,
+                                                      is_window_available);
 
   /* for each grpc_chttp2_stream that's become writable, frame it's data
      (according to available window sizes) and add to the output buffer */
@@ -329,10 +332,6 @@
     grpc_chttp2_transport_writing *transport_writing) {
   grpc_chttp2_stream_writing *stream_writing;
   grpc_chttp2_stream_global *stream_global;
-  bool is_window_available = transport_writing->outgoing_window > 0;
-
-  grpc_chttp2_list_flush_writing_stalled_by_transport(transport_writing,
-                                                      is_window_available);
 
   while (grpc_chttp2_list_pop_written_stream(
       transport_global, transport_writing, &stream_global, &stream_writing)) {
diff --git a/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
index 78295cf..ab12c12 100644
--- a/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
+++ b/src/csharp/Grpc.Core.Tests/GrpcEnvironmentTest.cs
@@ -84,7 +84,7 @@
         {
             var coreVersion = GrpcEnvironment.GetCoreVersionString();
             var parts = coreVersion.Split('.');
-            Assert.AreEqual(4, parts.Length);
+            Assert.AreEqual(3, parts.Length);
         }
     }
 }
diff --git a/src/csharp/Grpc.Core/Version.cs b/src/csharp/Grpc.Core/Version.cs
index d02b301..8a26bd8 100644
--- a/src/csharp/Grpc.Core/Version.cs
+++ b/src/csharp/Grpc.Core/Version.cs
@@ -34,4 +34,4 @@
 using System.Reflection;
 
 // The current version of gRPC C#.
-[assembly: AssemblyVersion(Grpc.Core.VersionInfo.CurrentVersion + ".0")]
+[assembly: AssemblyVersion(Grpc.Core.VersionInfo.CurrentAssemblyVersion)]
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index 6581390..4bd4f20 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -39,8 +39,13 @@
     public static class VersionInfo
     {
         /// <summary>
+        /// Current version of gRPC C# assemblies
+        /// </summary>
+        public const string CurrentAssemblyVersion = "0.14.0.0";
+
+        /// <summary>
         /// Current version of gRPC C#
         /// </summary>
-        public const string CurrentVersion = "0.13.0";
+        public const string CurrentVersion = "0.14.0-dev";
     }
 }
diff --git a/src/csharp/build_packages.bat b/src/csharp/build_packages.bat
index e423545..b7768f7 100644
--- a/src/csharp/build_packages.bat
+++ b/src/csharp/build_packages.bat
@@ -1,7 +1,7 @@
 @rem Builds gRPC NuGet packages
 
 @rem Current package versions
-set VERSION=0.13.0
+set VERSION=0.14.0-dev
 set PROTOBUF_VERSION=3.0.0-beta2
 
 @rem Packages that depend on prerelease packages (like Google.Protobuf) need to have prerelease suffix as well.
diff --git a/src/node/ext/timeval.cc b/src/node/ext/timeval.cc
index 64015e8..c8f8534 100644
--- a/src/node/ext/timeval.cc
+++ b/src/node/ext/timeval.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
  */
 
 #include <limits>
+#include <cstdint>
 
 #include "grpc/grpc.h"
 #include "grpc/support/time.h"
@@ -46,7 +47,7 @@
   } else if (millis == -std::numeric_limits<double>::infinity()) {
     return gpr_inf_past(GPR_CLOCK_REALTIME);
   } else {
-    return gpr_time_from_micros(static_cast<long>(millis * 1000),
+    return gpr_time_from_micros(static_cast<int64_t>(millis * 1000),
                                 GPR_CLOCK_REALTIME);
   }
 }
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h
similarity index 80%
rename from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
rename to src/objective-c/GRPCClient/GRPCCall+ChannelArg.h
index 8528be4..bd6b064 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,9 +30,17 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  */
+#import "GRPCCall.h"
 
-#import "GRPCChannel.h"
+/**
+ * Methods to configure GRPC channel options.
+ */
+@interface GRPCCall (ChannelArg)
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
+/**
+ * Use the provided @c userAgentPrefix at the beginning of the HTTP User Agent string for all calls
+ * to the specified @c host.
+ */
++ (void)setUserAgentPrefix:(NSString *)userAgentPrefix forHost:(NSString *)host;
+
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m
similarity index 76%
copy from src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
copy to src/objective-c/GRPCClient/GRPCCall+ChannelArg.m
index 8528be4..5f9932d 100644
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.h
+++ b/src/objective-c/GRPCClient/GRPCCall+ChannelArg.m
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,8 +31,19 @@
  *
  */
 
-#import "GRPCChannel.h"
+#import "GRPCCall+ChannelArg.h"
 
-@interface GRPCUnsecuredChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host NS_DESIGNATED_INITIALIZER;
+#import "private/GRPCHost.h"
+
+@implementation GRPCCall (ChannelArg)
+
++ (void)setUserAgentPrefix:(NSString *)userAgentPrefix forHost:(NSString *)host {
+  if (!host) {
+    [NSException raise:NSInvalidArgumentException
+                format:@"host and userAgentPrefix must be provided."];
+  }
+  GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
+  hostConfig.userAgentPrefix = userAgentPrefix;
+}
+
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.h b/src/objective-c/GRPCClient/private/GRPCChannel.h
index e2d19d5..8661ae6 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.h
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,18 +33,51 @@
 
 #import <Foundation/Foundation.h>
 
-struct grpc_channel;
+#include <grpc/grpc.h>
+
+struct grpc_channel_credentials;
+
 
 /**
  * Each separate instance of this class represents at least one TCP connection to the provided host.
- * Create them using one of the subclasses |GRPCSecureChannel| and |GRPCUnsecuredChannel|.
  */
 @interface GRPCChannel : NSObject
-@property(nonatomic, readonly) struct grpc_channel *unmanagedChannel;
+
+@property(nonatomic, readonly, nonnull) struct grpc_channel *unmanagedChannel;
+
+- (nullable instancetype)init NS_UNAVAILABLE;
 
 /**
- * This initializer takes ownership of the passed channel, and will destroy it when this object is
- * deallocated. It's illegal to pass the same grpc_channel to two different GRPCChannel objects.
+ * Creates a secure channel to the specified @c host using default credentials and channel
+ * arguments. If certificates could not be found to create a secure channel, then @c nil is
+ * returned.
  */
-- (instancetype)initWithChannel:(struct grpc_channel *)unmanagedChannel NS_DESIGNATED_INITIALIZER;
++ (nullable GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host;
+
+/**
+ * Creates a secure channel to the specified @c host using the specified @c pathToCertificates and 
+ * @c channelArgs. Only in tests should @c pathToCertificates be nil or
+ * @c GRPC_SSL_TARGET_NAME_OVERRIDE_ARG channel arg be set. Passing nil for @c pathToCertificates
+ * results in using the default root certificates distributed with the library. If certificates
+ * could not be found in any case, then @c nil is returned.
+ */
++ (nullable GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host
+                             pathToCertificates:(nullable NSString *)pathToCertificates
+                                    channelArgs:(nullable NSDictionary *)channelArgs;
+
+
+/**
+ * Creates a secure channel to the specified @c host using the specified @c credentials and
+ * @c channelArgs. Only in tests should @c GRPC_SSL_TARGET_NAME_OVERRIDE_ARG channel arg be set.
+ */
++ (nonnull GRPCChannel *)secureChannelWithHost:(nonnull NSString *)host
+    credentials:(nonnull struct grpc_channel_credentials *)credentials
+    channelArgs:(nullable NSDictionary *)channelArgs;
+
+/**
+ * Creates an insecure channel to the specified @c host using the specified @c channelArgs.
+ */
++ (nonnull GRPCChannel *)insecureChannelWithHost:(nonnull NSString *)host
+                                     channelArgs:(nullable NSDictionary *)channelArgs;
+
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCChannel.m b/src/objective-c/GRPCClient/private/GRPCChannel.m
index 4366e63..7e55a47 100644
--- a/src/objective-c/GRPCClient/private/GRPCChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCChannel.m
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -33,22 +33,114 @@
 
 #import "GRPCChannel.h"
 
-#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/string_util.h>
 
-@implementation GRPCChannel
-
-- (instancetype)init {
-  return [self initWithChannel:NULL];
+/**
+ * Returns @c grpc_channel_credentials from the specified @c path. If the file at the path could not
+ * be read then NULL is returned. If NULL is returned, @c errorPtr may not be NULL if there are
+ * details available describing what went wrong.
+ */
+static grpc_channel_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) {
+  // Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the
+  // issuer). Load them as UTF8 and produce an ASCII equivalent.
+  NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path
+                                                      encoding:NSUTF8StringEncoding
+                                                         error:errorPtr];
+  NSData *contentInASCII = [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding
+                                       allowLossyConversion:YES];
+  if (!contentInASCII.bytes) {
+    // Passing NULL to grpc_ssl_credentials_create produces behavior we don't want, so return.
+    return NULL;
+  }
+  return grpc_ssl_credentials_create(contentInASCII.bytes, NULL, NULL);
 }
 
-// Designated initializer
-- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel {
-  if (!unmanagedChannel) {
+void freeChannelArgs(grpc_channel_args *channel_args) {
+  for (size_t i = 0; i < channel_args->num_args; ++i) {
+    grpc_arg *arg = &channel_args->args[i];
+    gpr_free(arg->key);
+    if (arg->type == GRPC_ARG_STRING) {
+      gpr_free(arg->value.string);
+    }
+  }
+  gpr_free(channel_args);
+}
+
+/**
+ * Allocates a @c grpc_channel_args and populates it with the options specified in the
+ * @c dictionary. Keys must be @c NSString. If the value responds to @c @selector(UTF8String) then
+ * it will be mapped to @c GRPC_ARG_STRING. If not, it will be mapped to @c GRPC_ARG_INTEGER if the
+ * value responds to @c @selector(intValue). Otherwise, an exception will be raised. The caller of
+ * this function is responsible for calling @c freeChannelArgs on a non-NULL returned value.
+ */
+grpc_channel_args * buildChannelArgs(NSDictionary *dictionary) {
+  if (!dictionary) {
+    return NULL;
+  }
+
+  NSArray *keys = [dictionary allKeys];
+  NSUInteger argCount = [keys count];
+
+  grpc_channel_args *channelArgs = gpr_malloc(sizeof(grpc_channel_args));
+  channelArgs->num_args = argCount;
+  channelArgs->args = gpr_malloc(argCount * sizeof(grpc_arg));
+
+  // TODO(kriswuollett) Check that keys adhere to GRPC core library requirements
+
+  for (NSUInteger i = 0; i < argCount; ++i) {
+    grpc_arg *arg = &channelArgs->args[i];
+    arg->key = gpr_strdup([keys[i] UTF8String]);
+
+    id value = dictionary[keys[i]];
+    if ([value respondsToSelector:@selector(UTF8String)]) {
+      arg->type = GRPC_ARG_STRING;
+      arg->value.string = gpr_strdup([value UTF8String]);
+    } else if ([value respondsToSelector:@selector(intValue)]) {
+      arg->type = GRPC_ARG_INTEGER;
+      arg->value.integer = [value intValue];
+    } else {
+      [NSException raise:NSInvalidArgumentException
+                  format:@"Invalid value type: %@", [value class]];
+    }
+  }
+
+  return channelArgs;
+}
+
+@implementation GRPCChannel {
+  // Retain arguments to channel_create because they may not be used on the thread that invoked
+  // the channel_create function.
+  NSString *_host;
+  grpc_channel_args *_channelArgs;
+}
+
+
+- (instancetype)initWithHost:(NSString *)host
+                      secure:(BOOL)secure
+                 credentials:(struct grpc_channel_credentials *)credentials
+                 channelArgs:(NSDictionary *)channelArgs {
+  if (!host) {
+    [NSException raise:NSInvalidArgumentException format:@"host argument missing"];
+  }
+
+  if (secure && !credentials) {
     return nil;
   }
-  if ((self = [super init])) {
-    _unmanagedChannel = unmanagedChannel;
+
+  if (self = [super init]) {
+    _channelArgs = buildChannelArgs(channelArgs);
+    _host = [host copy];
+    if (secure) {
+      _unmanagedChannel = grpc_secure_channel_create(credentials, _host.UTF8String, _channelArgs,
+                                                     NULL);
+    } else {
+      _unmanagedChannel = grpc_insecure_channel_create(_host.UTF8String, _channelArgs, NULL);
+    }
   }
+
   return self;
 }
 
@@ -56,5 +148,61 @@
   // TODO(jcanizales): Be sure to add a test with a server that closes the connection prematurely,
   // as in the past that made this call to crash.
   grpc_channel_destroy(_unmanagedChannel);
+  freeChannelArgs(_channelArgs);
 }
+
++ (GRPCChannel *)secureChannelWithHost:(NSString *)host {
+  return [[GRPCChannel alloc] initWithHost:host secure:YES credentials:NULL channelArgs:NULL];
+}
+
++ (GRPCChannel *)secureChannelWithHost:(NSString *)host
+                    pathToCertificates:(NSString *)path
+                           channelArgs:(NSDictionary *)channelArgs {
+  // Load default SSL certificates once.
+  static grpc_channel_credentials *kDefaultCertificates;
+  static dispatch_once_t loading;
+  dispatch_once(&loading, ^{
+    NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem
+    // Do not use NSBundle.mainBundle, as it's nil for tests of library projects.
+    NSBundle *bundle = [NSBundle bundleForClass:self.class];
+    NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"];
+    NSError *error;
+    kDefaultCertificates = CertificatesAtPath(path, &error);
+    NSAssert(kDefaultCertificates, @"Could not read %@/%@.pem. This file, with the root "
+             "certificates, is needed to establish secure (TLS) connections. Because the file is "
+             "distributed with the gRPC library, this error is usually a sign that the library "
+             "wasn't configured correctly for your project. Error: %@",
+             bundle.bundlePath, defaultPath, error);
+  });
+
+  //TODO(jcanizales): Add NSError** parameter to the initializer.
+  grpc_channel_credentials *certificates = path
+      ? CertificatesAtPath(path, NULL)
+      : kDefaultCertificates;
+
+  return [[GRPCChannel alloc] initWithHost:host
+                                    secure:YES
+                               credentials:certificates
+                               channelArgs:channelArgs];
+}
+
+
++ (GRPCChannel *)secureChannelWithHost:(NSString *)host
+                           credentials:(struct grpc_channel_credentials *)credentials
+                           channelArgs:(NSDictionary *)channelArgs {
+  return [[GRPCChannel alloc] initWithHost:host
+                                    secure:YES
+                               credentials:credentials
+                               channelArgs:channelArgs];
+
+}
+
++ (GRPCChannel *)insecureChannelWithHost:(NSString *)host
+                             channelArgs:(NSDictionary *)channelArgs {
+  return [[GRPCChannel alloc] initWithHost:host
+                                    secure:NO
+                               credentials:NULL
+                               channelArgs:channelArgs];
+}
+
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.h b/src/objective-c/GRPCClient/private/GRPCHost.h
index 6b4f987..82c0ad6 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.h
+++ b/src/objective-c/GRPCClient/private/GRPCHost.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -39,6 +39,7 @@
 @interface GRPCHost : NSObject
 
 @property(nonatomic, readonly) NSString *address;
+@property(nonatomic, copy) NSString *userAgentPrefix;
 
 /** The following properties should only be modified for testing: */
 
diff --git a/src/objective-c/GRPCClient/private/GRPCHost.m b/src/objective-c/GRPCClient/private/GRPCHost.m
index a8cd3a0..eb1db89 100644
--- a/src/objective-c/GRPCClient/private/GRPCHost.m
+++ b/src/objective-c/GRPCClient/private/GRPCHost.m
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,11 +34,15 @@
 #import "GRPCHost.h"
 
 #include <grpc/grpc.h>
+#import <GRPCClient/GRPCCall+ChannelArg.h>
 
 #import "GRPCChannel.h"
 #import "GRPCCompletionQueue.h"
-#import "GRPCSecureChannel.h"
-#import "GRPCUnsecuredChannel.h"
+#import "NSDictionary+GRPC.h"
+
+// TODO(jcanizales): Generate the version in a standalone header, from templates. Like
+// templates/src/core/surface/version.c.template .
+#define GRPC_OBJC_VERSION_STRING @"0.13.0"
 
 @interface GRPCHost ()
 // TODO(mlumish): Investigate whether caching channels with strong links is a good idea.
@@ -106,13 +110,28 @@
 - (GRPCChannel *)channel {
   // Create it lazily, because we don't want to open a connection just because someone is
   // configuring a host.
+
   if (!_channel) {
+    NSMutableDictionary *args = [NSMutableDictionary dictionary];
+
+    // TODO(jcanizales): Add OS and device information (see
+    // https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#user-agents ).
+    NSString *userAgent = @"grpc-objc/" GRPC_OBJC_VERSION_STRING;
+    if (_userAgentPrefix) {
+      userAgent = [@[_userAgentPrefix, userAgent] componentsJoinedByString:@" "];
+    }
+    args[@GRPC_ARG_PRIMARY_USER_AGENT_STRING] = userAgent;
+
     if (_secure) {
-      _channel = [[GRPCSecureChannel alloc] initWithHost:_address
-                                      pathToCertificates:_pathToCertificates
-                                        hostNameOverride:_hostNameOverride];
+      if (_hostNameOverride) {
+        args[@GRPC_SSL_TARGET_NAME_OVERRIDE_ARG] = _hostNameOverride;
+      }
+
+      _channel = [GRPCChannel secureChannelWithHost:_address
+                                 pathToCertificates:_pathToCertificates
+                                        channelArgs:args];
     } else {
-      _channel = [[GRPCUnsecuredChannel alloc] initWithHost:_address];
+      _channel = [GRPCChannel insecureChannelWithHost:_address channelArgs:args];
     }
   }
   return _channel;
diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.h b/src/objective-c/GRPCClient/private/GRPCSecureChannel.h
deleted file mode 100644
index b82b9fe..0000000
--- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <grpc/grpc.h>
-
-#import "GRPCChannel.h"
-
-struct grpc_channel_credentials;
-
-@interface GRPCSecureChannel : GRPCChannel
-- (instancetype)initWithHost:(NSString *)host;
-
-/**
- * Only in tests shouldn't pathToCertificates or hostNameOverride be nil. Passing nil for
- * pathToCertificates results in using the default root certificates distributed with the library.
- */
-- (instancetype)initWithHost:(NSString *)host
-          pathToCertificates:(NSString *)path
-            hostNameOverride:(NSString *)hostNameOverride;
-
-/** The passed arguments aren't required to be valid beyond the invocation of this initializer. */
-- (instancetype)initWithHost:(NSString *)host
-                 credentials:(struct grpc_channel_credentials *)credentials
-                        args:(grpc_channel_args *)args NS_DESIGNATED_INITIALIZER;
-@end
diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
deleted file mode 100644
index a573c17..0000000
--- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#import "GRPCSecureChannel.h"
-
-#include <grpc/grpc_security.h>
-
-// Returns NULL if the file at path couldn't be read. In that case, if errorPtr isn't NULL,
-// *errorPtr will be an object describing what went wrong.
-static grpc_channel_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) {
-  // Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the
-  // issuer). Load them as UTF8 and produce an ASCII equivalent.
-  NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path
-                                                     encoding:NSUTF8StringEncoding
-                                                        error:errorPtr];
-  NSData *contentInASCII = [contentInUTF8 dataUsingEncoding:NSASCIIStringEncoding
-                                       allowLossyConversion:YES];
-  if (!contentInASCII.bytes) {
-    // Passing NULL to grpc_ssl_credentials_create produces behavior we don't want, so return.
-    return NULL;
-  }
-  return grpc_ssl_credentials_create(contentInASCII.bytes, NULL, NULL);
-}
-
-@implementation GRPCSecureChannel
-
-- (instancetype)initWithHost:(NSString *)host {
-  return [self initWithHost:host pathToCertificates:nil hostNameOverride:nil];
-}
-
-- (instancetype)initWithHost:(NSString *)host
-          pathToCertificates:(NSString *)path
-            hostNameOverride:(NSString *)hostNameOverride {
-  // Load default SSL certificates once.
-  static grpc_channel_credentials *kDefaultCertificates;
-  static dispatch_once_t loading;
-  dispatch_once(&loading, ^{
-    NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem
-    // Do not use NSBundle.mainBundle, as it's nil for tests of library projects.
-    NSBundle *bundle = [NSBundle bundleForClass:self.class];
-    NSString *path = [bundle pathForResource:defaultPath ofType:@"pem"];
-    NSError *error;
-    kDefaultCertificates = CertificatesAtPath(path, &error);
-    NSAssert(kDefaultCertificates, @"Could not read %@/%@.pem. This file, with the root "
-             "certificates, is needed to establish secure (TLS) connections. Because the file is "
-             "distributed with the gRPC library, this error is usually a sign that the library "
-             "wasn't configured correctly for your project. Error: %@",
-             bundle.bundlePath, defaultPath, error);
-  });
-
-  //TODO(jcanizales): Add NSError** parameter to the initializer.
-  grpc_channel_credentials *certificates = path
-      ? CertificatesAtPath(path, NULL)
-      : kDefaultCertificates;
-  if (!certificates) {
-    return nil;
-  }
-
-  // Ritual to pass the SSL host name override to the C library.
-  grpc_channel_args channelArgs;
-  grpc_arg nameOverrideArg;
-  channelArgs.num_args = 1;
-  channelArgs.args = &nameOverrideArg;
-  nameOverrideArg.type = GRPC_ARG_STRING;
-  nameOverrideArg.key = GRPC_SSL_TARGET_NAME_OVERRIDE_ARG;
-  // Cast const away. Hope C gRPC doesn't modify it!
-  nameOverrideArg.value.string = (char *) hostNameOverride.UTF8String;
-  grpc_channel_args *args = hostNameOverride ? &channelArgs : NULL;
-
-  return [self initWithHost:host credentials:certificates args:args];
-}
-
-- (instancetype)initWithHost:(NSString *)host
-                 credentials:(grpc_channel_credentials *)credentials
-                        args:(grpc_channel_args *)args {
-  return (self = [super
-              initWithChannel:grpc_secure_channel_create(
-                                  credentials, host.UTF8String, args, NULL)]);
-}
-
-// TODO(jcanizales): GRPCSecureChannel and GRPCUnsecuredChannel are just convenience initializers
-// for GRPCChannel. Move them into GRPCChannel, which will make the following unnecessary.
-- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel {
-  [NSException raise:NSInternalInconsistencyException format:@"use another initializer"];
-  return [self initWithHost:nil]; // silence warnings
-}
-
-@end
diff --git a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m b/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
deleted file mode 100644
index 15b6ffc..0000000
--- a/src/objective-c/GRPCClient/private/GRPCUnsecuredChannel.m
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#import "GRPCUnsecuredChannel.h"
-
-#include <grpc/grpc.h>
-
-@implementation GRPCUnsecuredChannel
-
-- (instancetype)initWithHost:(NSString *)host {
-  return (self = [super initWithChannel:grpc_insecure_channel_create(host.UTF8String, NULL, NULL)]);
-}
-
-// TODO(jcanizales): GRPCSecureChannel and GRPCUnsecuredChannel are just convenience initializers
-// for GRPCChannel. Move them into GRPCChannel, which will make the following unnecessary.
-- (instancetype)initWithChannel:(grpc_channel *)unmanagedChannel {
-  [NSException raise:NSInternalInconsistencyException format:@"use the other initializer"];
-  return [self initWithHost:nil]; // silence warnings
-}
-@end
diff --git a/src/python/grpcio/commands.py b/src/python/grpcio/commands.py
index 490d0f0..774e7ad 100644
--- a/src/python/grpcio/commands.py
+++ b/src/python/grpcio/commands.py
@@ -54,7 +54,10 @@
 
 BINARIES_REPOSITORY = os.environ.get(
     'GRPC_PYTHON_BINARIES_REPOSITORY',
-    'https://storage.googleapis.com/grpc-precompiled-binaries/python/')
+    'https://storage.googleapis.com/grpc-precompiled-binaries/python')
+
+USE_GRPC_CUSTOM_BDIST = bool(int(os.environ.get(
+    'GRPC_PYTHON_USE_CUSTOM_BDIST', '1')))
 
 CONF_PY_ADDENDUM = """
 extensions.append('sphinx.ext.napoleon')
@@ -135,7 +138,7 @@
 
   def initialize_options(self):
     install.install.initialize_options(self)
-    self.use_grpc_custom_bdist = False
+    self.use_grpc_custom_bdist = USE_GRPC_CUSTOM_BDIST
 
   def finalize_options(self):
     install.install.finalize_options(self)
@@ -143,22 +146,25 @@
   def run(self):
     if self.use_grpc_custom_bdist:
       try:
-        egg_path = _get_grpc_custom_bdist_egg(self.egg_name(True),
-                                              self.egg_name(False))
-      except CommandError as error:
-        sys.stderr.write(
-            '\nWARNING: Failed to acquire grpcio prebuilt binary:\n'
-            '{}.\n\n'.format(error.message))
-        raise
-      try:
-        self._run_bdist_retrieval_install(egg_path)
-      except Exception as error:
-        # if anything else happens (and given how there's no way to really know
-        # what's happening in setuptools here, I mean *anything*), warn the user
-        # and fall back to building from source.
-        sys.stderr.write(
-            '{}\nWARNING: Failed to install grpcio prebuilt binary.\n\n'
-                .format(traceback.format_exc()))
+        try:
+          egg_path = _get_grpc_custom_bdist_egg(self.egg_name(True),
+                                                self.egg_name(False))
+        except CommandError as error:
+          sys.stderr.write(
+              '\nWARNING: Failed to acquire grpcio prebuilt binary:\n'
+              '{}.\n\n'.format(error.message))
+          raise
+        try:
+          self._run_bdist_retrieval_install(egg_path)
+        except Exception as error:
+          # if anything else happens (and given how there's no way to really know
+          # what's happening in setuptools here, I mean *anything*), warn the user
+          # and fall back to building from source.
+          sys.stderr.write(
+              '{}\nWARNING: Failed to install grpcio prebuilt binary.\n\n'
+                  .format(traceback.format_exc()))
+          raise
+      except Exception:
         install.install.run(self)
     else:
       install.install.run(self)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
index 9e14b96..fa4ea99 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/records.pyx.pxi
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx
index f4b96cc..30cc7a1 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pyx
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
diff --git a/src/python/grpcio/grpc/_cython/imports.generated.c b/src/python/grpcio/grpc/_cython/imports.generated.c
index b818f34..817303c 100644
--- a/src/python/grpcio/grpc/_cython/imports.generated.c
+++ b/src/python/grpcio/grpc/_cython/imports.generated.c
@@ -41,7 +41,14 @@
 census_shutdown_type census_shutdown_import;
 census_supported_type census_supported_import;
 census_enabled_type census_enabled_import;
-census_context_serialize_type census_context_serialize_import;
+census_context_create_type census_context_create_import;
+census_context_destroy_type census_context_destroy_import;
+census_context_get_status_type census_context_get_status_import;
+census_context_initialize_iterator_type census_context_initialize_iterator_import;
+census_context_next_tag_type census_context_next_tag_import;
+census_context_get_tag_type census_context_get_tag_import;
+census_context_encode_type census_context_encode_import;
+census_context_decode_type census_context_decode_import;
 census_trace_mask_type census_trace_mask_import;
 census_set_trace_mask_type census_set_trace_mask_import;
 census_start_rpc_op_timestamp_type census_start_rpc_op_timestamp_import;
@@ -54,15 +61,6 @@
 census_trace_scan_start_type census_trace_scan_start_import;
 census_get_trace_record_type census_get_trace_record_import;
 census_trace_scan_end_type census_trace_scan_end_import;
-census_tag_set_create_type census_tag_set_create_import;
-census_tag_set_destroy_type census_tag_set_destroy_import;
-census_tag_set_get_create_status_type census_tag_set_get_create_status_import;
-census_tag_set_initialize_iterator_type census_tag_set_initialize_iterator_import;
-census_tag_set_next_tag_type census_tag_set_next_tag_import;
-census_tag_set_get_tag_by_key_type census_tag_set_get_tag_by_key_import;
-census_tag_set_encode_type census_tag_set_encode_import;
-census_tag_set_decode_type census_tag_set_decode_import;
-census_context_tag_set_type census_context_tag_set_import;
 census_record_values_type census_record_values_import;
 census_view_create_type census_view_create_import;
 census_view_delete_type census_view_delete_import;
@@ -303,7 +301,14 @@
   census_shutdown_import = (census_shutdown_type) GetProcAddress(library, "census_shutdown");
   census_supported_import = (census_supported_type) GetProcAddress(library, "census_supported");
   census_enabled_import = (census_enabled_type) GetProcAddress(library, "census_enabled");
-  census_context_serialize_import = (census_context_serialize_type) GetProcAddress(library, "census_context_serialize");
+  census_context_create_import = (census_context_create_type) GetProcAddress(library, "census_context_create");
+  census_context_destroy_import = (census_context_destroy_type) GetProcAddress(library, "census_context_destroy");
+  census_context_get_status_import = (census_context_get_status_type) GetProcAddress(library, "census_context_get_status");
+  census_context_initialize_iterator_import = (census_context_initialize_iterator_type) GetProcAddress(library, "census_context_initialize_iterator");
+  census_context_next_tag_import = (census_context_next_tag_type) GetProcAddress(library, "census_context_next_tag");
+  census_context_get_tag_import = (census_context_get_tag_type) GetProcAddress(library, "census_context_get_tag");
+  census_context_encode_import = (census_context_encode_type) GetProcAddress(library, "census_context_encode");
+  census_context_decode_import = (census_context_decode_type) GetProcAddress(library, "census_context_decode");
   census_trace_mask_import = (census_trace_mask_type) GetProcAddress(library, "census_trace_mask");
   census_set_trace_mask_import = (census_set_trace_mask_type) GetProcAddress(library, "census_set_trace_mask");
   census_start_rpc_op_timestamp_import = (census_start_rpc_op_timestamp_type) GetProcAddress(library, "census_start_rpc_op_timestamp");
@@ -316,15 +321,6 @@
   census_trace_scan_start_import = (census_trace_scan_start_type) GetProcAddress(library, "census_trace_scan_start");
   census_get_trace_record_import = (census_get_trace_record_type) GetProcAddress(library, "census_get_trace_record");
   census_trace_scan_end_import = (census_trace_scan_end_type) GetProcAddress(library, "census_trace_scan_end");
-  census_tag_set_create_import = (census_tag_set_create_type) GetProcAddress(library, "census_tag_set_create");
-  census_tag_set_destroy_import = (census_tag_set_destroy_type) GetProcAddress(library, "census_tag_set_destroy");
-  census_tag_set_get_create_status_import = (census_tag_set_get_create_status_type) GetProcAddress(library, "census_tag_set_get_create_status");
-  census_tag_set_initialize_iterator_import = (census_tag_set_initialize_iterator_type) GetProcAddress(library, "census_tag_set_initialize_iterator");
-  census_tag_set_next_tag_import = (census_tag_set_next_tag_type) GetProcAddress(library, "census_tag_set_next_tag");
-  census_tag_set_get_tag_by_key_import = (census_tag_set_get_tag_by_key_type) GetProcAddress(library, "census_tag_set_get_tag_by_key");
-  census_tag_set_encode_import = (census_tag_set_encode_type) GetProcAddress(library, "census_tag_set_encode");
-  census_tag_set_decode_import = (census_tag_set_decode_type) GetProcAddress(library, "census_tag_set_decode");
-  census_context_tag_set_import = (census_context_tag_set_type) GetProcAddress(library, "census_context_tag_set");
   census_record_values_import = (census_record_values_type) GetProcAddress(library, "census_record_values");
   census_view_create_import = (census_view_create_type) GetProcAddress(library, "census_view_create");
   census_view_delete_import = (census_view_delete_type) GetProcAddress(library, "census_view_delete");
diff --git a/src/python/grpcio/grpc/_cython/imports.generated.h b/src/python/grpcio/grpc/_cython/imports.generated.h
index 2a8a910..6d0a6e0 100644
--- a/src/python/grpcio/grpc/_cython/imports.generated.h
+++ b/src/python/grpcio/grpc/_cython/imports.generated.h
@@ -73,9 +73,30 @@
 typedef int(*census_enabled_type)(void);
 extern census_enabled_type census_enabled_import;
 #define census_enabled census_enabled_import
-typedef size_t(*census_context_serialize_type)(const census_context *context, char *buffer, size_t buf_size);
-extern census_context_serialize_type census_context_serialize_import;
-#define census_context_serialize census_context_serialize_import
+typedef census_context *(*census_context_create_type)(const census_context *base, const census_tag *tags, int ntags, census_context_status const **status);
+extern census_context_create_type census_context_create_import;
+#define census_context_create census_context_create_import
+typedef void(*census_context_destroy_type)(census_context *context);
+extern census_context_destroy_type census_context_destroy_import;
+#define census_context_destroy census_context_destroy_import
+typedef const census_context_status *(*census_context_get_status_type)(const census_context *context);
+extern census_context_get_status_type census_context_get_status_import;
+#define census_context_get_status census_context_get_status_import
+typedef void(*census_context_initialize_iterator_type)(const census_context *context, census_context_iterator *iterator);
+extern census_context_initialize_iterator_type census_context_initialize_iterator_import;
+#define census_context_initialize_iterator census_context_initialize_iterator_import
+typedef int(*census_context_next_tag_type)(census_context_iterator *iterator, census_tag *tag);
+extern census_context_next_tag_type census_context_next_tag_import;
+#define census_context_next_tag census_context_next_tag_import
+typedef int(*census_context_get_tag_type)(const census_context *context, const char *key, census_tag *tag);
+extern census_context_get_tag_type census_context_get_tag_import;
+#define census_context_get_tag census_context_get_tag_import
+typedef char *(*census_context_encode_type)(const census_context *context, char *buffer, size_t buf_size, size_t *print_buf_size, size_t *bin_buf_size);
+extern census_context_encode_type census_context_encode_import;
+#define census_context_encode census_context_encode_import
+typedef census_context *(*census_context_decode_type)(const char *buffer, size_t size, const char *bin_buffer, size_t bin_size);
+extern census_context_decode_type census_context_decode_import;
+#define census_context_decode census_context_decode_import
 typedef int(*census_trace_mask_type)(const census_context *context);
 extern census_trace_mask_type census_trace_mask_import;
 #define census_trace_mask census_trace_mask_import
@@ -112,37 +133,10 @@
 typedef void(*census_trace_scan_end_type)();
 extern census_trace_scan_end_type census_trace_scan_end_import;
 #define census_trace_scan_end census_trace_scan_end_import
-typedef census_tag_set *(*census_tag_set_create_type)(const census_tag_set *base, const census_tag *tags, int ntags, census_tag_set_create_status const **status);
-extern census_tag_set_create_type census_tag_set_create_import;
-#define census_tag_set_create census_tag_set_create_import
-typedef void(*census_tag_set_destroy_type)(census_tag_set *tags);
-extern census_tag_set_destroy_type census_tag_set_destroy_import;
-#define census_tag_set_destroy census_tag_set_destroy_import
-typedef const census_tag_set_create_status *(*census_tag_set_get_create_status_type)(const census_tag_set *tags);
-extern census_tag_set_get_create_status_type census_tag_set_get_create_status_import;
-#define census_tag_set_get_create_status census_tag_set_get_create_status_import
-typedef void(*census_tag_set_initialize_iterator_type)(const census_tag_set *tags, census_tag_set_iterator *iterator);
-extern census_tag_set_initialize_iterator_type census_tag_set_initialize_iterator_import;
-#define census_tag_set_initialize_iterator census_tag_set_initialize_iterator_import
-typedef int(*census_tag_set_next_tag_type)(census_tag_set_iterator *iterator, census_tag *tag);
-extern census_tag_set_next_tag_type census_tag_set_next_tag_import;
-#define census_tag_set_next_tag census_tag_set_next_tag_import
-typedef int(*census_tag_set_get_tag_by_key_type)(const census_tag_set *tags, const char *key, census_tag *tag);
-extern census_tag_set_get_tag_by_key_type census_tag_set_get_tag_by_key_import;
-#define census_tag_set_get_tag_by_key census_tag_set_get_tag_by_key_import
-typedef char *(*census_tag_set_encode_type)(const census_tag_set *tags, char *buffer, size_t buf_size, size_t *print_buf_size, size_t *bin_buf_size);
-extern census_tag_set_encode_type census_tag_set_encode_import;
-#define census_tag_set_encode census_tag_set_encode_import
-typedef census_tag_set *(*census_tag_set_decode_type)(const char *buffer, size_t size, const char *bin_buffer, size_t bin_size);
-extern census_tag_set_decode_type census_tag_set_decode_import;
-#define census_tag_set_decode census_tag_set_decode_import
-typedef census_tag_set *(*census_context_tag_set_type)(census_context *context);
-extern census_context_tag_set_type census_context_tag_set_import;
-#define census_context_tag_set census_context_tag_set_import
 typedef void(*census_record_values_type)(census_context *context, census_value *values, size_t nvalues);
 extern census_record_values_type census_record_values_import;
 #define census_record_values census_record_values_import
-typedef census_view *(*census_view_create_type)(uint32_t metric_id, const census_tag_set *tags, const census_aggregation *aggregations, size_t naggregations);
+typedef census_view *(*census_view_create_type)(uint32_t metric_id, const census_context *tags, const census_aggregation *aggregations, size_t naggregations);
 extern census_view_create_type census_view_create_import;
 #define census_view_create census_view_create_import
 typedef void(*census_view_delete_type)(census_view *view);
@@ -154,7 +148,7 @@
 typedef size_t(*census_view_naggregations_type)(const census_view *view);
 extern census_view_naggregations_type census_view_naggregations_import;
 #define census_view_naggregations census_view_naggregations_import
-typedef const census_tag_set *(*census_view_tags_type)(const census_view *view);
+typedef const census_context *(*census_view_tags_type)(const census_view *view);
 extern census_view_tags_type census_view_tags_import;
 #define census_view_tags census_view_tags_import
 typedef const census_aggregation *(*census_view_aggregrations_type)(const census_view *view);
@@ -661,22 +655,22 @@
 typedef gpr_timespec(*gpr_time_sub_type)(gpr_timespec a, gpr_timespec b);
 extern gpr_time_sub_type gpr_time_sub_import;
 #define gpr_time_sub gpr_time_sub_import
-typedef gpr_timespec(*gpr_time_from_micros_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_micros_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_micros_type gpr_time_from_micros_import;
 #define gpr_time_from_micros gpr_time_from_micros_import
-typedef gpr_timespec(*gpr_time_from_nanos_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_nanos_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_nanos_type gpr_time_from_nanos_import;
 #define gpr_time_from_nanos gpr_time_from_nanos_import
-typedef gpr_timespec(*gpr_time_from_millis_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_millis_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_millis_type gpr_time_from_millis_import;
 #define gpr_time_from_millis gpr_time_from_millis_import
-typedef gpr_timespec(*gpr_time_from_seconds_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_seconds_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_seconds_type gpr_time_from_seconds_import;
 #define gpr_time_from_seconds gpr_time_from_seconds_import
-typedef gpr_timespec(*gpr_time_from_minutes_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_minutes_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_minutes_type gpr_time_from_minutes_import;
 #define gpr_time_from_minutes gpr_time_from_minutes_import
-typedef gpr_timespec(*gpr_time_from_hours_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_hours_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_hours_type gpr_time_from_hours_import;
 #define gpr_time_from_hours gpr_time_from_hours_import
 typedef int32_t(*gpr_time_to_millis_type)(gpr_timespec timespec);
diff --git a/tools/dockerfile/grpc_sanity/Dockerfile b/src/python/grpcio/grpc_version.py
similarity index 60%
copy from tools/dockerfile/grpc_sanity/Dockerfile
copy to src/python/grpcio/grpc_version.py
index 8833141..75b88cf 100644
--- a/tools/dockerfile/grpc_sanity/Dockerfile
+++ b/src/python/grpcio/grpc_version.py
@@ -27,57 +27,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Dockerfile for running gRPC sanity tests
+# AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
 
-FROM debian:jessie
-
-# Install Git and basic packages.
-RUN apt-get update && apt-get install -y \
-  autoconf \
-  autotools-dev \
-  build-essential \
-  bzip2 \
-  ccache \
-  curl \
-  gcc \
-  gcc-multilib \
-  git \
-  golang \
-  gyp \
-  lcov \
-  libc6 \
-  libc6-dbg \
-  libc6-dev \
-  libgtest-dev \
-  libtool \
-  make \
-  perl \
-  strace \
-  python-dev \
-  python-setuptools \
-  python-yaml \
-  telnet \
-  unzip \
-  wget \
-  zip && apt-get clean
-
-##################
-# Sanity test dependencies
-RUN apt-get update && apt-get install -y python-pip
-RUN pip install simplejson mako
-
-##################
-# Docker "inception".
-# Note this is quite the ugly hack.
-# This makes sure that the docker binary we inject has its dependencies.
-RUN curl https://get.docker.com/ | sh
-RUN apt-get remove --purge -y docker-engine
-
-##################
-# Build profiling
-RUN apt-get install -y time
-
-RUN mkdir /var/local/jenkins
-
-# Define the default command.
-CMD ["bash"]
+VERSION='0.14.0.dev0'
diff --git a/src/ruby/ext/grpc/extconf.rb b/src/ruby/ext/grpc/extconf.rb
index 426a6e6..b7c6cb3 100644
--- a/src/ruby/ext/grpc/extconf.rb
+++ b/src/ruby/ext/grpc/extconf.rb
@@ -66,6 +66,8 @@
   grpc_lib_dir = File.join(grpc_root, 'libs', grpc_config)
 end
 
+ENV['MACOSX_DEPLOYMENT_TARGET'] = '10.7'
+
 unless File.exist?(File.join(grpc_lib_dir, 'libgrpc.a')) or windows
   ENV['AR'] = RbConfig::CONFIG['AR'] + ' rcs'
   ENV['CC'] = RbConfig::CONFIG['CC']
@@ -75,6 +77,7 @@
 
   ENV['EMBED_OPENSSL'] = 'true'
   ENV['EMBED_ZLIB'] = 'true'
+  ENV['ARCH_FLAGS'] = RbConfig::CONFIG['ARCH_FLAG']
   ENV['ARCH_FLAGS'] = '-arch i386 -arch x86_64' if RUBY_PLATFORM =~ /darwin/
 
   output_dir = File.expand_path(RbConfig::CONFIG['topdir'])
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index d1e4875..0e6badb 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -229,7 +229,7 @@
   }
   grpc_channel_watch_connectivity_state(
       ch,
-      NUM2LONG(last_state),
+      (grpc_connectivity_state)NUM2LONG(last_state),
       grpc_rb_time_timeval(deadline, /* absolute time */ 0),
       cq,
       ROBJECT(tag));
diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
index 45e9b47..618ae5e 100644
--- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h
+++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h
@@ -655,22 +655,22 @@
 typedef gpr_timespec(*gpr_time_sub_type)(gpr_timespec a, gpr_timespec b);
 extern gpr_time_sub_type gpr_time_sub_import;
 #define gpr_time_sub gpr_time_sub_import
-typedef gpr_timespec(*gpr_time_from_micros_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_micros_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_micros_type gpr_time_from_micros_import;
 #define gpr_time_from_micros gpr_time_from_micros_import
-typedef gpr_timespec(*gpr_time_from_nanos_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_nanos_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_nanos_type gpr_time_from_nanos_import;
 #define gpr_time_from_nanos gpr_time_from_nanos_import
-typedef gpr_timespec(*gpr_time_from_millis_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_millis_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_millis_type gpr_time_from_millis_import;
 #define gpr_time_from_millis gpr_time_from_millis_import
-typedef gpr_timespec(*gpr_time_from_seconds_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_seconds_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_seconds_type gpr_time_from_seconds_import;
 #define gpr_time_from_seconds gpr_time_from_seconds_import
-typedef gpr_timespec(*gpr_time_from_minutes_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_minutes_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_minutes_type gpr_time_from_minutes_import;
 #define gpr_time_from_minutes gpr_time_from_minutes_import
-typedef gpr_timespec(*gpr_time_from_hours_type)(long x, gpr_clock_type clock_type);
+typedef gpr_timespec(*gpr_time_from_hours_type)(int64_t x, gpr_clock_type clock_type);
 extern gpr_time_from_hours_type gpr_time_from_hours_import;
 #define gpr_time_from_hours gpr_time_from_hours_import
 typedef int32_t(*gpr_time_to_millis_type)(gpr_timespec timespec);
diff --git a/src/ruby/ext/grpc/rb_server_credentials.c b/src/ruby/ext/grpc/rb_server_credentials.c
index f866aec..4ea59b6 100644
--- a/src/ruby/ext/grpc/rb_server_credentials.c
+++ b/src/ruby/ext/grpc/rb_server_credentials.c
@@ -177,7 +177,7 @@
   VALUE key = Qnil;
   VALUE key_cert = Qnil;
   int auth_client = 0;
-  int num_key_certs = 0;
+  long num_key_certs = 0;
   int i;
 
   if (NIL_P(force_client_auth) ||
diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb
index 956e022..9cbd36a 100644
--- a/src/ruby/lib/grpc/version.rb
+++ b/src/ruby/lib/grpc/version.rb
@@ -29,5 +29,5 @@
 
 # GRPC contains the General RPC module.
 module GRPC
-  VERSION = '0.12.0'
+  VERSION = '0.14.0-dev'
 end
diff --git a/templates/Makefile.template b/templates/Makefile.template
index 1a38e26..9942514 100644
--- a/templates/Makefile.template
+++ b/templates/Makefile.template
@@ -276,7 +276,7 @@
   Q = @
   endif
 
-  VERSION = ${settings.version.major}.${settings.version.minor}.${settings.version.micro}.${settings.version.build}
+  VERSION = ${settings.core_version}
 
   CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
   CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
@@ -320,7 +320,7 @@
   ifeq ($(SYSTEM),MINGW32)
   SHARED_EXT = dll
   SHARED_PREFIX =
-  SHARED_VERSION = -${settings.version.major}
+  SHARED_VERSION = -${settings.core_version.major}
   else ifeq ($(SYSTEM),Darwin)
   SHARED_EXT = dylib
   SHARED_PREFIX = lib
@@ -1286,7 +1286,7 @@
   ifeq ($(SYSTEM),MINGW32)
   	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}-imp.a $(prefix)/lib/lib${lib.name}-imp.a
   else ifneq ($(SYSTEM),Darwin)
-  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so.${settings.version.major}
+  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so.${settings.core_version.major}
   	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so
   endif
   % endif
@@ -1304,7 +1304,7 @@
   ifeq ($(SYSTEM),MINGW32)
   	$(Q) $(INSTALL) $(LIBDIR)/$(CONFIG)/lib${lib.name}-imp.a $(prefix)/lib/lib${lib.name}-imp.a
   else ifneq ($(SYSTEM),Darwin)
-  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so.${settings.version.major}
+  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so.${settings.core_version.major}
   	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) $(prefix)/lib/lib${lib.name}.so
   endif
   % endif
@@ -1578,8 +1578,8 @@
   ifeq ($(SYSTEM),Darwin)
   	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -install_name $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) -dynamiclib -o ${out_libbase}.$(SHARED_EXT) ${common}${libs}
   else
-  	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,lib${lib.name}.so.${settings.version.major} -o ${out_libbase}.$(SHARED_EXT) ${common}${libs}
-  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) ${out_libbase}.so.${settings.version.major}
+  	$(Q) ${ld} ${ldflags} -L$(LIBDIR)/$(CONFIG) -shared -Wl,-soname,lib${lib.name}.so.${settings.core_version.major} -o ${out_libbase}.$(SHARED_EXT) ${common}${libs}
+  	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) ${out_libbase}.so.${settings.core_version.major}
   	$(Q) ln -sf $(SHARED_PREFIX)${lib.name}$(SHARED_VERSION).$(SHARED_EXT) ${out_libbase}.so
   endif
   endif
diff --git a/templates/grpc.gemspec.template b/templates/grpc.gemspec.template
index 9d034dd..c4987a6 100644
--- a/templates/grpc.gemspec.template
+++ b/templates/grpc.gemspec.template
@@ -16,7 +16,6 @@
     s.license       = 'BSD-3-Clause'
 
     s.required_ruby_version = '>= 2.0.0'
-    s.requirements << 'libgrpc ~> 0.11.0 needs to be installed'
 
     s.files = %w( Makefile )
     s.files += %w( etc/roots.pem )
diff --git a/templates/package.json.template b/templates/package.json.template
index ed4dca5..ec44497 100644
--- a/templates/package.json.template
+++ b/templates/package.json.template
@@ -2,7 +2,7 @@
 --- |
   {
     "name": "grpc",
-    "version": "0.12.0",
+    "version": "${settings.node_version}",
     "author": "Google Inc.",
     "description": "gRPC Library for Node",
     "homepage": "http://www.grpc.io/",
diff --git a/templates/src/core/surface/version.c.template b/templates/src/core/surface/version.c.template
index 4788dc4..f2b3cfd 100644
--- a/templates/src/core/surface/version.c.template
+++ b/templates/src/core/surface/version.c.template
@@ -38,5 +38,4 @@
   
   #include <grpc/grpc.h>
   
-  const char *grpc_version_string(void) { \
-  return "${settings.version.major}.${settings.version.minor}.${settings.version.micro}.${settings.version.build}"; }
+  const char *grpc_version_string(void) { return "${settings.core_version}"; }
diff --git a/templates/src/csharp/Grpc.Core/VersionInfo.cs.template b/templates/src/csharp/Grpc.Core/VersionInfo.cs.template
index 48197ba..59864fa 100644
--- a/templates/src/csharp/Grpc.Core/VersionInfo.cs.template
+++ b/templates/src/csharp/Grpc.Core/VersionInfo.cs.template
@@ -41,8 +41,13 @@
       public static class VersionInfo
       {
           /// <summary>
+          /// Current version of gRPC C# assemblies
+          /// </summary>
+          public const string CurrentAssemblyVersion = "${settings.version.major}.${settings.version.minor}.${settings.version.patch}.0";
+
+          /// <summary>
           /// Current version of gRPC C#
           /// </summary>
-          public const string CurrentVersion = "${settings.version.major}.${settings.version.minor}.${settings.version.micro}";
+          public const string CurrentVersion = "${settings.csharp_version}";
       }
   }
diff --git a/templates/src/csharp/build_packages.bat.template b/templates/src/csharp/build_packages.bat.template
index 847653b..b855126 100644
--- a/templates/src/csharp/build_packages.bat.template
+++ b/templates/src/csharp/build_packages.bat.template
@@ -3,7 +3,7 @@
   @rem Builds gRPC NuGet packages
   
   @rem Current package versions
-  set VERSION=${settings.version.major}.${settings.version.minor}.${settings.version.micro}
+  set VERSION=${settings.csharp_version}
   set PROTOBUF_VERSION=3.0.0-beta2
   
   @rem Packages that depend on prerelease packages (like Google.Protobuf) need to have prerelease suffix as well.
diff --git a/templates/src/python/grpcio/grpc_version.py.template b/templates/src/python/grpcio/grpc_version.py.template
new file mode 100644
index 0000000..aaacab1
--- /dev/null
+++ b/templates/src/python/grpcio/grpc_version.py.template
@@ -0,0 +1,34 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!!
+
+  VERSION='${settings.python_version.pep440()}'
diff --git a/templates/src/ruby/lib/grpc/version.rb.template b/templates/src/ruby/lib/grpc/version.rb.template
new file mode 100644
index 0000000..a47d2d8
--- /dev/null
+++ b/templates/src/ruby/lib/grpc/version.rb.template
@@ -0,0 +1,35 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+  # GRPC contains the General RPC module.
+  module GRPC
+    VERSION = '${settings.ruby_version}'
+  end
diff --git a/templates/tools/dockerfile/apt_get_basic.include b/templates/tools/dockerfile/apt_get_basic.include
new file mode 100644
index 0000000..9237e7d
--- /dev/null
+++ b/templates/tools/dockerfile/apt_get_basic.include
@@ -0,0 +1,33 @@
+# Install Git and basic packages.
+RUN apt-get update && apt-get install -y ${'\\'}
+  autoconf ${'\\'}
+  autotools-dev ${'\\'}
+  build-essential ${'\\'}
+  bzip2 ${'\\'}
+  ccache ${'\\'}
+  curl ${'\\'}
+  gcc ${'\\'}
+  gcc-multilib ${'\\'}
+  git ${'\\'}
+  golang ${'\\'}
+  gyp ${'\\'}
+  lcov ${'\\'}
+  libc6 ${'\\'}
+  libc6-dbg ${'\\'}
+  libc6-dev ${'\\'}
+  libgtest-dev ${'\\'}
+  libtool ${'\\'}
+  make ${'\\'}
+  perl ${'\\'}
+  strace ${'\\'}
+  python-dev ${'\\'}
+  python-setuptools ${'\\'}
+  python-yaml ${'\\'}
+  telnet ${'\\'}
+  unzip ${'\\'}
+  wget ${'\\'}
+  zip && apt-get clean
+
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
diff --git a/templates/tools/dockerfile/ccache_setup.include b/templates/tools/dockerfile/ccache_setup.include
new file mode 100644
index 0000000..2a2de7f
--- /dev/null
+++ b/templates/tools/dockerfile/ccache_setup.include
@@ -0,0 +1,7 @@
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
diff --git a/templates/tools/dockerfile/csharp_deps.include b/templates/tools/dockerfile/csharp_deps.include
new file mode 100644
index 0000000..489dc44
--- /dev/null
+++ b/templates/tools/dockerfile/csharp_deps.include
@@ -0,0 +1,16 @@
+#================
+# C# dependencies
+
+# Update to a newer version of mono
+RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
+RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list
+RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
+RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
+RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
+
+# Install dependencies
+RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y ${'\\'}
+    mono-devel ${'\\'}
+    ca-certificates-mono ${'\\'}
+    nuget ${'\\'}
+    && apt-get clean
diff --git a/templates/tools/dockerfile/cxx_deps.include b/templates/tools/dockerfile/cxx_deps.include
new file mode 100644
index 0000000..14831c1
--- /dev/null
+++ b/templates/tools/dockerfile/cxx_deps.include
@@ -0,0 +1,3 @@
+#=================
+# C++ dependencies
+RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
diff --git a/templates/tools/dockerfile/node_deps.include b/templates/tools/dockerfile/node_deps.include
new file mode 100644
index 0000000..7d37d67
--- /dev/null
+++ b/templates/tools/dockerfile/node_deps.include
@@ -0,0 +1,7 @@
+#==================
+# Node dependencies
+
+# Install nvm
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+RUN /bin/bash -l -c "nvm install 0.12 && npm config set cache /tmp/npm-cache"
diff --git a/templates/tools/dockerfile/php_deps.include b/templates/tools/dockerfile/php_deps.include
new file mode 100644
index 0000000..739049b
--- /dev/null
+++ b/templates/tools/dockerfile/php_deps.include
@@ -0,0 +1,13 @@
+#=================
+# PHP dependencies
+
+# Install dependencies
+
+RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' ${'\\'}
+    >> /etc/apt/sources.list.d/dotdeb.list"
+RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' ${'\\'}
+    >> /etc/apt/sources.list.d/dotdeb.list"
+RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
+
+RUN apt-get update && apt-get install -y ${'\\'}
+    git php5 php5-dev phpunit unzip
diff --git a/templates/tools/dockerfile/python_deps.include b/templates/tools/dockerfile/python_deps.include
new file mode 100644
index 0000000..a559f96
--- /dev/null
+++ b/templates/tools/dockerfile/python_deps.include
@@ -0,0 +1,14 @@
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y ${'\\'}
+    python-all-dev ${'\\'}
+    python3-all-dev ${'\\'}
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 tox
diff --git a/templates/tools/dockerfile/ruby_deps.include b/templates/tools/dockerfile/ruby_deps.include
new file mode 100644
index 0000000..a8ee3ec
--- /dev/null
+++ b/templates/tools/dockerfile/ruby_deps.include
@@ -0,0 +1,14 @@
+#==================
+# Ruby dependencies
+
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+RUN \curl -sSL https://get.rvm.io | bash -s stable
+
+# Install Ruby 2.1
+RUN /bin/bash -l -c "rvm install ruby-2.1"
+RUN /bin/bash -l -c "rvm use --default ruby-2.1"
+RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
+RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
+RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
+RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
diff --git a/templates/tools/dockerfile/run_tests_addons.include b/templates/tools/dockerfile/run_tests_addons.include
new file mode 100644
index 0000000..27ac67f
--- /dev/null
+++ b/templates/tools/dockerfile/run_tests_addons.include
@@ -0,0 +1,7 @@
+<%include file="ccache_setup.include"/>
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
+
+RUN mkdir /var/local/jenkins
diff --git a/templates/tools/dockerfile/test/csharp_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/csharp_jessie_x64/Dockerfile.template
new file mode 100644
index 0000000..1c01dea
--- /dev/null
+++ b/templates/tools/dockerfile/test/csharp_jessie_x64/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../csharp_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
diff --git a/templates/tools/dockerfile/test/cxx_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/cxx_jessie_x64/Dockerfile.template
new file mode 100644
index 0000000..842c534
--- /dev/null
+++ b/templates/tools/dockerfile/test/cxx_jessie_x64/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../cxx_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/cxx_jessie_x86/Dockerfile.template b/templates/tools/dockerfile/test/cxx_jessie_x86/Dockerfile.template
new file mode 100644
index 0000000..4e95cdd
--- /dev/null
+++ b/templates/tools/dockerfile/test/cxx_jessie_x86/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM 32bit/debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../cxx_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template
new file mode 100644
index 0000000..10551a5
--- /dev/null
+++ b/templates/tools/dockerfile/test/node_jessie_x64/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../node_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/php_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/php_jessie_x64/Dockerfile.template
new file mode 100644
index 0000000..d717239
--- /dev/null
+++ b/templates/tools/dockerfile/test/php_jessie_x64/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../php_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/python_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/python_jessie_x64/Dockerfile.template
new file mode 100644
index 0000000..9e68b3e
--- /dev/null
+++ b/templates/tools/dockerfile/test/python_jessie_x64/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../python_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/ruby_jessie_x64/Dockerfile.template b/templates/tools/dockerfile/test/ruby_jessie_x64/Dockerfile.template
new file mode 100644
index 0000000..db777be
--- /dev/null
+++ b/templates/tools/dockerfile/test/ruby_jessie_x64/Dockerfile.template
@@ -0,0 +1,39 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  <%include file="../../ruby_deps.include"/>
+  <%include file="../../run_tests_addons.include"/>
+  # Define the default command.
+  CMD ["bash"]
+  
\ No newline at end of file
diff --git a/templates/tools/dockerfile/test/sanity/Dockerfile.template b/templates/tools/dockerfile/test/sanity/Dockerfile.template
new file mode 100644
index 0000000..bbdb848
--- /dev/null
+++ b/templates/tools/dockerfile/test/sanity/Dockerfile.template
@@ -0,0 +1,51 @@
+%YAML 1.2
+--- |
+  # Copyright 2015-2016, Google Inc.
+  # All rights reserved.
+  #
+  # Redistribution and use in source and binary forms, with or without
+  # modification, are permitted provided that the following conditions are
+  # met:
+  #
+  #     * Redistributions of source code must retain the above copyright
+  # notice, this list of conditions and the following disclaimer.
+  #     * Redistributions in binary form must reproduce the above
+  # copyright notice, this list of conditions and the following disclaimer
+  # in the documentation and/or other materials provided with the
+  # distribution.
+  #     * Neither the name of Google Inc. nor the names of its
+  # contributors may be used to endorse or promote products derived from
+  # this software without specific prior written permission.
+  #
+  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+  # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+  # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+  # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+  # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+  # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+  # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+  # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  
+  FROM debian:jessie
+  
+  <%include file="../../apt_get_basic.include"/>
+  #========================
+  # Sanity test dependencies
+  RUN apt-get update && apt-get install -y python-pip
+  RUN pip install simplejson mako
+
+  #===================
+  # Docker "inception"
+  # Note this is quite the ugly hack.
+  # This makes sure that the docker binary we inject has its dependencies.
+  RUN curl https://get.docker.com/ | sh
+  RUN apt-get remove --purge -y docker-engine
+  
+  RUN mkdir /var/local/jenkins
+  
+  # Define the default command.
+  CMD ["bash"]
+  
diff --git a/templates/tools/doxygen/Doxyfile.include b/templates/tools/doxygen/Doxyfile.include
index 21ef8a8..8b0c528 100644
--- a/templates/tools/doxygen/Doxyfile.include
+++ b/templates/tools/doxygen/Doxyfile.include
@@ -57,7 +57,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = ${settings.version.major}.${settings.version.minor}.${settings.version.micro}.${settings.version.build}
+PROJECT_NUMBER         = ${settings.core_version if packagename=='Core' else settings.cpp_version}
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/test/core/statistics/census_log_tests.c b/test/core/statistics/census_log_tests.c
index aac20fd..77cc57d 100644
--- a/test/core/statistics/census_log_tests.c
+++ b/test/core/statistics/census_log_tests.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -237,8 +237,8 @@
   gpr_timespec interval;
   int counter = 0;
   printf("   Reader starting\n");
-  interval = gpr_time_from_micros(args->read_iteration_interval_in_msec * 1000,
-                                  GPR_TIMESPAN);
+  interval = gpr_time_from_micros(
+      (int64_t)args->read_iteration_interval_in_msec * 1000, GPR_TIMESPAN);
   gpr_mu_lock(args->mu);
   while (!args->stop_flag && records_read < args->total_records) {
     gpr_cv_wait(&args->stop, args->mu, interval);
diff --git a/test/core/support/sync_test.c b/test/core/support/sync_test.c
index 0149bc3..d311eb1 100644
--- a/test/core/support/sync_test.c
+++ b/test/core/support/sync_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -251,7 +251,7 @@
   gpr_timespec start = gpr_now(GPR_CLOCK_REALTIME);
   gpr_timespec time_taken;
   gpr_timespec deadline = gpr_time_add(
-      start, gpr_time_from_micros(timeout_s * 1000000, GPR_TIMESPAN));
+      start, gpr_time_from_micros((int64_t)timeout_s * 1000000, GPR_TIMESPAN));
   fprintf(stderr, "%s:", name);
   while (gpr_time_cmp(gpr_now(GPR_CLOCK_REALTIME), deadline) < 0) {
     iterations <<= 1;
diff --git a/test/core/support/time_test.c b/test/core/support/time_test.c
index fc26f94..6cc3786 100644
--- a/test/core/support/time_test.c
+++ b/test/core/support/time_test.c
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -125,15 +125,15 @@
   }
 
   /* Test possible overflow in conversion of -ve values. */
-  x = gpr_time_from_micros(-(LONG_MAX - 999997), GPR_TIMESPAN);
+  x = gpr_time_from_micros(-(INT64_MAX - 999997), GPR_TIMESPAN);
   GPR_ASSERT(x.tv_sec < 0);
   GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < GPR_NS_PER_SEC);
 
-  x = gpr_time_from_nanos(-(LONG_MAX - 999999997), GPR_TIMESPAN);
+  x = gpr_time_from_nanos(-(INT64_MAX - 999999997), GPR_TIMESPAN);
   GPR_ASSERT(x.tv_sec < 0);
   GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < GPR_NS_PER_SEC);
 
-  x = gpr_time_from_millis(-(LONG_MAX - 997), GPR_TIMESPAN);
+  x = gpr_time_from_millis(-(INT64_MAX - 997), GPR_TIMESPAN);
   GPR_ASSERT(x.tv_sec < 0);
   GPR_ASSERT(x.tv_nsec >= 0 && x.tv_nsec < GPR_NS_PER_SEC);
 
diff --git a/test/core/transport/chttp2/timeout_encoding_test.c b/test/core/transport/chttp2/timeout_encoding_test.c
index f0e8ec3..483e79f 100644
--- a/test/core/transport/chttp2/timeout_encoding_test.c
+++ b/test/core/transport/chttp2/timeout_encoding_test.c
@@ -93,7 +93,7 @@
 }
 
 void decode_suite(char ext,
-                  gpr_timespec (*answer)(long x, gpr_clock_type clock)) {
+                  gpr_timespec (*answer)(int64_t x, gpr_clock_type clock)) {
   long test_vals[] = {1,       12,       123,       1234,     12345,   123456,
                       1234567, 12345678, 123456789, 98765432, 9876543, 987654,
                       98765,   9876,     987,       98,       9};
diff --git a/test/core/util/test_config.h b/test/core/util/test_config.h
index 15b7174..f6bb2e1 100644
--- a/test/core/util/test_config.h
+++ b/test/core/util/test_config.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -54,16 +54,16 @@
   (GRPC_TEST_SLOWDOWN_BUILD_FACTOR * GRPC_TEST_SLOWDOWN_MACHINE_FACTOR * \
    g_fixture_slowdown_factor)
 
-#define GRPC_TIMEOUT_SECONDS_TO_DEADLINE(x)                               \
-  gpr_time_add(                                                           \
-      gpr_now(GPR_CLOCK_MONOTONIC),                                       \
-      gpr_time_from_millis((long)(GRPC_TEST_SLOWDOWN_FACTOR * 1e3 * (x)), \
+#define GRPC_TIMEOUT_SECONDS_TO_DEADLINE(x)                                  \
+  gpr_time_add(                                                              \
+      gpr_now(GPR_CLOCK_MONOTONIC),                                          \
+      gpr_time_from_millis((int64_t)(GRPC_TEST_SLOWDOWN_FACTOR * 1e3 * (x)), \
                            GPR_TIMESPAN))
 
-#define GRPC_TIMEOUT_MILLIS_TO_DEADLINE(x)                                \
-  gpr_time_add(                                                           \
-      gpr_now(GPR_CLOCK_MONOTONIC),                                       \
-      gpr_time_from_micros((long)(GRPC_TEST_SLOWDOWN_FACTOR * 1e3 * (x)), \
+#define GRPC_TIMEOUT_MILLIS_TO_DEADLINE(x)                                   \
+  gpr_time_add(                                                              \
+      gpr_now(GPR_CLOCK_MONOTONIC),                                          \
+      gpr_time_from_micros((int64_t)(GRPC_TEST_SLOWDOWN_FACTOR * 1e3 * (x)), \
                            GPR_TIMESPAN))
 
 #ifndef GRPC_TEST_CUSTOM_PICK_PORT
diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc
index 4c7caa9..e246c0b 100644
--- a/test/cpp/end2end/thread_stress_test.cc
+++ b/test/cpp/end2end/thread_stress_test.cc
@@ -56,7 +56,9 @@
 using std::chrono::system_clock;
 
 const int kNumThreads = 100;  // Number of threads
-const int kNumRpcs = 1000;    // Number of RPCs per thread
+const int kNumAsyncSendThreads = 2;
+const int kNumAsyncReceiveThreads = 50;
+const int kNumRpcs = 1000;  // Number of RPCs per thread
 
 namespace grpc {
 namespace testing {
@@ -273,7 +275,7 @@
     for (int i = 0; i < num_rpcs; ++i) {
       AsyncClientCall* call = new AsyncClientCall;
       EchoRequest request;
-      request.set_message("Hello");
+      request.set_message("Hello: " + std::to_string(i));
       call->response_reader =
           common_.GetStub()->AsyncEcho(&call->context, request, &cq_);
       call->response_reader->Finish(&call->response, &call->status,
@@ -290,7 +292,9 @@
       bool ok = false;
       if (!cq_.Next(&got_tag, &ok)) break;
       AsyncClientCall* call = static_cast<AsyncClientCall*>(got_tag);
-      GPR_ASSERT(ok);
+      if (!ok) {
+        gpr_log(GPR_DEBUG, "Error: %d", call->status.error_code());
+      }
       delete call;
 
       bool notify;
@@ -315,22 +319,22 @@
 TEST_F(AsyncClientEnd2endTest, ThreadStress) {
   common_.ResetStub();
   std::vector<std::thread*> send_threads, completion_threads;
-  for (int i = 0; i < kNumThreads / 2; ++i) {
+  for (int i = 0; i < kNumAsyncReceiveThreads; ++i) {
     completion_threads.push_back(new std::thread(
         &AsyncClientEnd2endTest_ThreadStress_Test::AsyncCompleteRpc, this));
   }
-  for (int i = 0; i < kNumThreads / 2; ++i) {
+  for (int i = 0; i < kNumAsyncSendThreads; ++i) {
     send_threads.push_back(
         new std::thread(&AsyncClientEnd2endTest_ThreadStress_Test::AsyncSendRpc,
                         this, kNumRpcs));
   }
-  for (int i = 0; i < kNumThreads / 2; ++i) {
+  for (int i = 0; i < kNumAsyncSendThreads; ++i) {
     send_threads[i]->join();
     delete send_threads[i];
   }
 
   Wait();
-  for (int i = 0; i < kNumThreads / 2; ++i) {
+  for (int i = 0; i < kNumAsyncReceiveThreads; ++i) {
     completion_threads[i]->join();
     delete completion_threads[i];
   }
diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc
index 6b6294b..f3f8f37 100644
--- a/test/cpp/qps/client_async.cc
+++ b/test/cpp/qps/client_async.cc
@@ -96,8 +96,7 @@
       std::function<
           std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>(
               BenchmarkService::Stub*, grpc::ClientContext*, const RequestType&,
-              CompletionQueue*)>
-          start_req,
+              CompletionQueue*)> start_req,
       std::function<void(grpc::Status, ResponseType*)> on_done)
       : ClientRpcContext(channel_id),
         context_(),
@@ -143,8 +142,7 @@
   std::function<void(grpc::Status, ResponseType*)> callback_;
   std::function<std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>(
       BenchmarkService::Stub*, grpc::ClientContext*, const RequestType&,
-      CompletionQueue*)>
-      start_req_;
+      CompletionQueue*)> start_req_;
   grpc::Status status_;
   double start_;
   std::unique_ptr<grpc::ClientAsyncResponseReader<ResponseType>>
@@ -164,12 +162,11 @@
   using ClientImpl<StubType, RequestType>::cores_;
   using ClientImpl<StubType, RequestType>::channels_;
   using ClientImpl<StubType, RequestType>::request_;
-  AsyncClient(
-      const ClientConfig& config,
-      std::function<ClientRpcContext*(int, StubType*, const RequestType&)>
-          setup_ctx,
-      std::function<std::unique_ptr<StubType>(std::shared_ptr<Channel>)>
-          create_stub)
+  AsyncClient(const ClientConfig& config,
+              std::function<ClientRpcContext*(int, StubType*,
+                                              const RequestType&)> setup_ctx,
+              std::function<std::unique_ptr<StubType>(std::shared_ptr<Channel>)>
+                  create_stub)
       : ClientImpl<StubType, RequestType>(config, create_stub),
         num_async_threads_(NumThreads(config)),
         channel_lock_(new std::mutex[config.client_channels()]),
@@ -411,8 +408,7 @@
       std::function<std::unique_ptr<
           grpc::ClientAsyncReaderWriter<RequestType, ResponseType>>(
           BenchmarkService::Stub*, grpc::ClientContext*, CompletionQueue*,
-          void*)>
-          start_req,
+          void*)> start_req,
       std::function<void(grpc::Status, ResponseType*)> on_done)
       : ClientRpcContext(channel_id),
         context_(),
@@ -464,10 +460,10 @@
   ResponseType response_;
   bool (ClientRpcContextStreamingImpl::*next_state_)(bool, Histogram*);
   std::function<void(grpc::Status, ResponseType*)> callback_;
-  std::function<std::unique_ptr<
-      grpc::ClientAsyncReaderWriter<RequestType, ResponseType>>(
-      BenchmarkService::Stub*, grpc::ClientContext*, CompletionQueue*, void*)>
-      start_req_;
+  std::function<
+      std::unique_ptr<grpc::ClientAsyncReaderWriter<RequestType, ResponseType>>(
+          BenchmarkService::Stub*, grpc::ClientContext*, CompletionQueue*,
+          void*)> start_req_;
   grpc::Status status_;
   double start_;
   std::unique_ptr<grpc::ClientAsyncReaderWriter<RequestType, ResponseType>>
@@ -511,8 +507,7 @@
       int channel_id, grpc::GenericStub* stub, const ByteBuffer& req,
       std::function<std::unique_ptr<grpc::GenericClientAsyncReaderWriter>(
           grpc::GenericStub*, grpc::ClientContext*,
-          const grpc::string& method_name, CompletionQueue*, void*)>
-          start_req,
+          const grpc::string& method_name, CompletionQueue*, void*)> start_req,
       std::function<void(grpc::Status, ByteBuffer*)> on_done)
       : ClientRpcContext(channel_id),
         context_(),
@@ -569,8 +564,7 @@
   std::function<void(grpc::Status, ByteBuffer*)> callback_;
   std::function<std::unique_ptr<grpc::GenericClientAsyncReaderWriter>(
       grpc::GenericStub*, grpc::ClientContext*, const grpc::string&,
-      CompletionQueue*, void*)>
-      start_req_;
+      CompletionQueue*, void*)> start_req_;
   grpc::Status status_;
   double start_;
   std::unique_ptr<grpc::GenericClientAsyncReaderWriter> stream_;
diff --git a/test/cpp/qps/driver.h b/test/cpp/qps/driver.h
index 4b2b400..3af61f7 100644
--- a/test/cpp/qps/driver.h
+++ b/test/cpp/qps/driver.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
diff --git a/test/cpp/util/time_test.cc b/test/cpp/util/time_test.cc
index 1e501df..48c6ce7 100644
--- a/test/cpp/util/time_test.cc
+++ b/test/cpp/util/time_test.cc
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright 2015, Google Inc.
+ * Copyright 2015-2016, Google Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,7 @@
 class TimeTest : public ::testing::Test {};
 
 TEST_F(TimeTest, AbsolutePointTest) {
-  long us = 10000000L;
+  int64_t us = 10000000L;
   gpr_timespec ts = gpr_time_from_micros(us, GPR_TIMESPAN);
   ts.clock_type = GPR_CLOCK_REALTIME;
   system_clock::time_point tp{microseconds(us)};
diff --git a/test/distrib/csharp/run_distrib_test.sh b/test/distrib/csharp/run_distrib_test.sh
index 5a01c91..8ddb4c4 100755
--- a/test/distrib/csharp/run_distrib_test.sh
+++ b/test/distrib/csharp/run_distrib_test.sh
@@ -32,7 +32,7 @@
 
 cd $(dirname $0)
 
-unzip "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets.zip" -d TestNugetFeed
+unzip -o "$EXTERNAL_GIT_ROOT/input_artifacts/csharp_nugets.zip" -d TestNugetFeed
 
 # TODO(jtattermusch): replace the version number
 ./update_version.sh 0.13.0
diff --git a/test/distrib/csharp/update_version.sh b/test/distrib/csharp/update_version.sh
index 569f7ff..f2554e8 100755
--- a/test/distrib/csharp/update_version.sh
+++ b/test/distrib/csharp/update_version.sh
@@ -33,4 +33,4 @@
 cd $(dirname $0)
 
 # Replaces version placeholder with value provided as first argument.
-sed -i "s/__GRPC_NUGET_VERSION__/$1/g" DistribTest/packages.config DistribTest/DistribTest.csproj
+sed -ibak "s/__GRPC_NUGET_VERSION__/$1/g" DistribTest/packages.config DistribTest/DistribTest.csproj
diff --git a/test/distrib/node/run_distrib_test.sh b/test/distrib/node/run_distrib_test.sh
index 90637cc..ac9e7d7 100755
--- a/test/distrib/node/run_distrib_test.sh
+++ b/test/distrib/node/run_distrib_test.sh
@@ -32,7 +32,12 @@
 
 cd $(dirname $0)
 
-nvm install $1
+NODE_VERSION="$1"
+
+# make sure nvm is available
+source ~/.nvm/nvm.sh || true
+
+nvm install $NODE_VERSION
 
 npm install -g node-static
 
diff --git a/test/distrib/python/distribtest.py b/test/distrib/python/distribtest.py
index 428ffe2..66c1f88 100644
--- a/test/distrib/python/distribtest.py
+++ b/test/distrib/python/distribtest.py
@@ -1,3 +1,32 @@
+# Copyright 2015-2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 from grpc.beta import implementations
 
 # This code doesn't do much but makes sure the native extension is loaded
diff --git a/test/distrib/python/run_distrib_test.sh b/test/distrib/python/run_distrib_test.sh
index a185bcb..08856ad 100755
--- a/test/distrib/python/run_distrib_test.sh
+++ b/test/distrib/python/run_distrib_test.sh
@@ -42,17 +42,17 @@
   exit 1
 fi
 
-# TODO(jtattermusch): this shouldn't be required
-pip install --upgrade six
+PIP=pip2
+which $PIP || PIP=pip
+PYTHON=python2
+which $PYTHON || PYTHON=python
 
-# TODO(jtattermusch): if these don't get preinstalled, pip tries to install them
-# with --use-grpc-custom-bdist option, which obviously fails.
-pip install --upgrade enum34
-pip install --upgrade futures
+# TODO(jtattermusch): this shouldn't be required
+$PIP install --upgrade six
 
 GRPC_PYTHON_BINARIES_REPOSITORY="${BDIST_DIR}" \
-    pip install \
-    "${SDIST_ARCHIVE}" \
-    --install-option="--use-grpc-custom-bdist"
+    $PIP install \
+    "${SDIST_ARCHIVE}"
 
-python distribtest.py
+$PYTHON distribtest.py
+
diff --git a/third_party/rake-compiler-dock/Dockerfile b/third_party/rake-compiler-dock/Dockerfile
index 28623c3..a8f5b8a 100644
--- a/third_party/rake-compiler-dock/Dockerfile
+++ b/third_party/rake-compiler-dock/Dockerfile
@@ -1,7 +1,7 @@
 FROM ubuntu:14.04
 
 RUN apt-get -y update && \
-    apt-get install -y curl git-core mingw-w64 xz-utils build-essential wget unzip
+    apt-get install -y curl git-core mingw-w64 xz-utils build-essential gcc-multilib wget unzip
 
 RUN mkdir -p /opt/mingw && \
     curl -SL http://downloads.sourceforge.net/mingw-w64/i686-w64-mingw32-gcc-4.7.2-release-linux64_rubenvb.tar.xz | \
@@ -103,12 +103,25 @@
     export MAKE=\"make -j`nproc`\" CFLAGS='-s -O1 -fno-omit-frame-pointer -fno-fast-math' && \
     rake-compiler cross-ruby VERSION=2.3.0 HOST=i686-w64-mingw32 && \
     rake-compiler cross-ruby VERSION=2.3.0 HOST=x86_64-w64-mingw32 && \
+    rake-compiler cross-ruby VERSION=2.3.0 HOST=x86_64-linux-gnu && \
     rake-compiler cross-ruby VERSION=2.2.2 HOST=i686-w64-mingw32 && \
     rake-compiler cross-ruby VERSION=2.2.2 HOST=x86_64-w64-mingw32 && \
-    rake-compiler cross-ruby VERSION=2.1.6 HOST=i686-w64-mingw32 && \
-    rake-compiler cross-ruby VERSION=2.1.6 HOST=x86_64-w64-mingw32 && \
+    rake-compiler cross-ruby VERSION=2.2.2 HOST=x86_64-linux-gnu && \
+    rake-compiler cross-ruby VERSION=2.1.5 HOST=i686-w64-mingw32 && \
+    rake-compiler cross-ruby VERSION=2.1.5 HOST=x86_64-w64-mingw32 && \
+    rake-compiler cross-ruby VERSION=2.1.5 HOST=x86_64-linux-gnu && \
     rake-compiler cross-ruby VERSION=2.0.0-p645 HOST=i686-w64-mingw32 && \
     rake-compiler cross-ruby VERSION=2.0.0-p645 HOST=x86_64-w64-mingw32 && \
+    rake-compiler cross-ruby VERSION=2.0.0-p645 HOST=x86_64-linux-gnu && \
+    rm -rf ~/.rake-compiler/tmp/builds ~/.rake-compiler/sources && \
+    find /usr/local/rvm -type d -print0 | sudo xargs -0 chmod g+sw "
+
+RUN bash -c "rvm use 2.3.0 --default && \
+    export MAKE=\"make -j`nproc`\" CFLAGS='-m32 -s -O1 -fno-omit-frame-pointer -fno-fast-math' LDFLAGS='-m32' && \
+    rake-compiler cross-ruby VERSION=2.3.0 HOST=i686-linux-gnu && \
+    rake-compiler cross-ruby VERSION=2.2.2 HOST=i686-linux-gnu && \
+    rake-compiler cross-ruby VERSION=2.1.5 HOST=i686-linux-gnu && \
+    rake-compiler cross-ruby VERSION=2.0.0-p645 HOST=i686-linux-gnu && \
     rm -rf ~/.rake-compiler/tmp/builds ~/.rake-compiler/sources && \
     find /usr/local/rvm -type d -print0 | sudo xargs -0 chmod g+sw "
 
@@ -151,6 +164,6 @@
 # Install sudoers configuration
 RUN cp /tmp/build/sudoers /etc/sudoers.d/rake-compiler-dock
 
-ENV RUBY_CC_VERSION 2.3.0:2.2.2:2.1.6:2.0.0
+ENV RUBY_CC_VERSION 2.3.0:2.2.2:2.1.5:2.0.0
 
 CMD bash
diff --git a/tools/buildgen/build-cleaner.py b/tools/buildgen/build-cleaner.py
index 37fedec..49a3644 100755
--- a/tools/buildgen/build-cleaner.py
+++ b/tools/buildgen/build-cleaner.py
@@ -38,7 +38,6 @@
 TEST = (os.environ.get('TEST', 'false') == 'true')
 
 _TOP_LEVEL_KEYS = ['settings', 'proto_deps', 'filegroups', 'libs', 'targets', 'vspackages']
-_VERSION_KEYS = ['major', 'minor', 'micro', 'build']
 _ELEM_KEYS = [
     'name',
     'cpu_cost',
@@ -83,8 +82,6 @@
   with open(filename) as f:
     js = yaml.load(f)
   js = rebuild_as_ordered_dict(js, _TOP_LEVEL_KEYS)
-  js['settings']['version'] = rebuild_as_ordered_dict(
-      js['settings']['version'], _VERSION_KEYS)
   for grp in ['filegroups', 'libs', 'targets']:
     if grp not in js: continue
     js[grp] = sorted([clean_elem(x) for x in js[grp]],
diff --git a/tools/buildgen/plugins/expand_version.py b/tools/buildgen/plugins/expand_version.py
new file mode 100755
index 0000000..4600c32
--- /dev/null
+++ b/tools/buildgen/plugins/expand_version.py
@@ -0,0 +1,94 @@
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Buildgen .proto files list plugin.
+
+This parses the list of targets from the yaml build file, and creates
+a list called "protos" that contains all of the proto file names.
+
+"""
+
+
+import re
+
+LANGUAGES = [
+  'core', 
+  'cpp', 
+  'csharp', 
+  'node', 
+  'objc', 
+  'php',
+  'python', 
+  'ruby', 
+  ]
+
+class Version:
+
+  def __init__(self, s):
+    if '-' in s:
+      s, self.tag = s.split('-')
+    self.major, self.minor, self.patch = [int(x) for x in s.split('.')]
+
+  def __str__(self):
+    """Version string in a somewhat idiomatic style for most languages"""
+    s = '%d.%d.%d' % (self.major, self.minor, self.patch)
+    if self.tag:
+      s += '-%s' % self.tag
+    return s
+
+  def pep440(self):
+    """Version string in Python PEP440 style"""
+    s = '%d.%d.%d' % (self.major, self.minor, self.patch)
+    if self.tag:
+      # we need to translate from grpc version tags to pep440 version
+      # tags; this code is likely to be a little ad-hoc
+      if self.tag == 'dev':
+        s += '.dev0'
+      elif len(self.tag) >= 3 and self.tag[0:3] == 'pre':
+        s += 'rc%d' % int(self.tag[3:])
+      else:
+        raise Exception('Don\'t know how to translate version tag "%s" to pep440' % self.tag)
+    return s
+
+def mako_plugin(dictionary):
+  """Expand version numbers:
+     - for each language, ensure there's a language_version tag in
+       settings (defaulting to the master version tag)
+     - expand version strings to major, minor, patch, and tag
+  """
+
+  settings = dictionary['settings']
+  master_version = Version(settings['version'])
+  settings['version'] = master_version
+  for language in LANGUAGES:
+    version_tag = '%s_version' % language
+    if version_tag in settings:
+      settings[version_tag] = Version(settings[version_tag])
+    else:
+      settings[version_tag] = master_version
diff --git a/tools/dockerfile/grpc_sanity/Dockerfile b/tools/distrib/build_ruby_environment_macos.sh
similarity index 60%
copy from tools/dockerfile/grpc_sanity/Dockerfile
copy to tools/distrib/build_ruby_environment_macos.sh
index 8833141..ff3a388 100644
--- a/tools/dockerfile/grpc_sanity/Dockerfile
+++ b/tools/distrib/build_ruby_environment_macos.sh
@@ -1,3 +1,4 @@
+#!/bin/bash
 # Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
@@ -27,57 +28,34 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Dockerfile for running gRPC sanity tests
+set -ex
 
-FROM debian:jessie
+rm -rf ~/.rake-compiler
 
-# Install Git and basic packages.
-RUN apt-get update && apt-get install -y \
-  autoconf \
-  autotools-dev \
-  build-essential \
-  bzip2 \
-  ccache \
-  curl \
-  gcc \
-  gcc-multilib \
-  git \
-  golang \
-  gyp \
-  lcov \
-  libc6 \
-  libc6-dbg \
-  libc6-dev \
-  libgtest-dev \
-  libtool \
-  make \
-  perl \
-  strace \
-  python-dev \
-  python-setuptools \
-  python-yaml \
-  telnet \
-  unzip \
-  wget \
-  zip && apt-get clean
+CROSS_RUBY=`mktemp tmpfile.XXXXXXXX`
 
-##################
-# Sanity test dependencies
-RUN apt-get update && apt-get install -y python-pip
-RUN pip install simplejson mako
+curl https://raw.githubusercontent.com/rake-compiler/rake-compiler/v0.9.5/tasks/bin/cross-ruby.rake > $CROSS_RUBY
 
-##################
-# Docker "inception".
-# Note this is quite the ugly hack.
-# This makes sure that the docker binary we inject has its dependencies.
-RUN curl https://get.docker.com/ | sh
-RUN apt-get remove --purge -y docker-engine
+patch $CROSS_RUBY << EOF
+--- cross-ruby.rake	2016-02-05 16:26:53.000000000 -0800
++++ cross-ruby.rake.patched	2016-02-05 16:27:33.000000000 -0800
+@@ -133,7 +133,8 @@
+     "--host=#{MINGW_HOST}",
+     "--target=#{MINGW_TARGET}",
+     "--build=#{RUBY_BUILD}",
+-    '--enable-shared',
++    '--enable-static',
++    '--disable-shared',
+     '--disable-install-doc',
+     '--without-tk',
+     '--without-tcl'
+EOF
 
-##################
-# Build profiling
-RUN apt-get install -y time
+MAKE="make -j8"
 
-RUN mkdir /var/local/jenkins
+for v in 2.3.0 2.2.2 2.1.5 2.0.0-p645 ; do
+  rake -f $CROSS_RUBY cross-ruby VERSION=$v HOST=x86_64-darwin11
+done
 
-# Define the default command.
-CMD ["bash"]
+sed 's/x86_64-darwin-11/universal-darwin/' ~/.rake-compiler/config.yml > $CROSS_RUBY
+mv $CROSS_RUBY ~/.rake-compiler/config.yml
diff --git a/tools/dockerfile/distribtest/csharp_centos7_x64/Dockerfile b/tools/dockerfile/distribtest/csharp_centos7_x64/Dockerfile
index 17e9698..03b5b36 100644
--- a/tools/dockerfile/distribtest/csharp_centos7_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/csharp_centos7_x64/Dockerfile
@@ -33,6 +33,5 @@
 RUN yum-config-manager --add-repo http://download.mono-project.com/repo/centos/
 
 RUN yum install -y mono
-RUN yum install -y git
 RUN yum install -y unzip
 RUN yum install -y nuget
diff --git a/tools/dockerfile/distribtest/csharp_jessie_x64/Dockerfile b/tools/dockerfile/distribtest/csharp_jessie_x64/Dockerfile
index 840ecf0..1cadba3 100644
--- a/tools/dockerfile/distribtest/csharp_jessie_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/csharp_jessie_x64/Dockerfile
@@ -40,4 +40,4 @@
     ca-certificates-mono \
     nuget
 
-RUN apt-get update && apt-get install -y git unzip
+RUN apt-get update && apt-get install -y unzip
diff --git a/tools/dockerfile/distribtest/csharp_jessie_x86/Dockerfile b/tools/dockerfile/distribtest/csharp_jessie_x86/Dockerfile
index 3a50da4..be96282 100644
--- a/tools/dockerfile/distribtest/csharp_jessie_x86/Dockerfile
+++ b/tools/dockerfile/distribtest/csharp_jessie_x86/Dockerfile
@@ -40,4 +40,4 @@
     ca-certificates-mono \
     nuget
 
-RUN apt-get update && apt-get install -y git unzip
+RUN apt-get update && apt-get install -y unzip
diff --git a/tools/dockerfile/distribtest/csharp_ubuntu1404_x64/Dockerfile b/tools/dockerfile/distribtest/csharp_ubuntu1404_x64/Dockerfile
index 901c981..3d04d03 100644
--- a/tools/dockerfile/distribtest/csharp_ubuntu1404_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/csharp_ubuntu1404_x64/Dockerfile
@@ -37,4 +37,4 @@
     ca-certificates-mono \
     nuget
 
-RUN apt-get update && apt-get install -y git unzip
+RUN apt-get update && apt-get install -y unzip
diff --git a/tools/dockerfile/distribtest/csharp_ubuntu1504_x64/Dockerfile b/tools/dockerfile/distribtest/csharp_ubuntu1504_x64/Dockerfile
index 1b8d454..5eec570 100644
--- a/tools/dockerfile/distribtest/csharp_ubuntu1504_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/csharp_ubuntu1504_x64/Dockerfile
@@ -37,4 +37,4 @@
     ca-certificates-mono \
     nuget
 
-RUN apt-get update && apt-get install -y git unzip
+RUN apt-get update && apt-get install -y unzip
diff --git a/tools/dockerfile/distribtest/csharp_ubuntu1510_x64/Dockerfile b/tools/dockerfile/distribtest/csharp_ubuntu1510_x64/Dockerfile
index a6c26a4..a6d60fb 100644
--- a/tools/dockerfile/distribtest/csharp_ubuntu1510_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/csharp_ubuntu1510_x64/Dockerfile
@@ -37,4 +37,4 @@
     ca-certificates-mono \
     nuget
 
-RUN apt-get update && apt-get install -y git unzip
+RUN apt-get update && apt-get install -y unzip
diff --git a/tools/dockerfile/distribtest/csharp_ubuntu1604_x64/Dockerfile b/tools/dockerfile/distribtest/csharp_ubuntu1604_x64/Dockerfile
index c6a8634..6147270 100644
--- a/tools/dockerfile/distribtest/csharp_ubuntu1604_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/csharp_ubuntu1604_x64/Dockerfile
@@ -34,4 +34,4 @@
     ca-certificates-mono \
     nuget
 
-RUN apt-get update && apt-get install -y git unzip
+RUN apt-get update && apt-get install -y unzip
diff --git a/tools/dockerfile/distribtest/csharp_wheezy_x64/Dockerfile b/tools/dockerfile/distribtest/csharp_wheezy_x64/Dockerfile
index dd865e8..9039c3c 100644
--- a/tools/dockerfile/distribtest/csharp_wheezy_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/csharp_wheezy_x64/Dockerfile
@@ -29,4 +29,4 @@
 
 FROM mono:4.2.2.30
 
-RUN apt-get update && apt-get install -y git unzip
+RUN apt-get update && apt-get install -y unzip
diff --git a/tools/dockerfile/distribtest/node_centos7_x64/Dockerfile b/tools/dockerfile/distribtest/node_centos7_x64/Dockerfile
index 9c1f5ee..f6e1664 100644
--- a/tools/dockerfile/distribtest/node_centos7_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/node_centos7_x64/Dockerfile
@@ -29,7 +29,6 @@
 
 FROM centos:7
 
-RUN yum install -y git
 RUN yum install -y curl
 
 # Install nvm
diff --git a/tools/dockerfile/distribtest/node_jessie_x64/Dockerfile b/tools/dockerfile/distribtest/node_jessie_x64/Dockerfile
index 69a0715..4ca5e86 100644
--- a/tools/dockerfile/distribtest/node_jessie_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/node_jessie_x64/Dockerfile
@@ -29,7 +29,7 @@
 
 FROM debian:jessie
 
-RUN apt-get update && apt-get install -y curl git
+RUN apt-get update && apt-get install -y curl
 
 # Install nvm
 RUN touch .profile
diff --git a/tools/dockerfile/distribtest/node_jessie_x86/Dockerfile b/tools/dockerfile/distribtest/node_jessie_x86/Dockerfile
index 173c703..8b97d8b 100644
--- a/tools/dockerfile/distribtest/node_jessie_x86/Dockerfile
+++ b/tools/dockerfile/distribtest/node_jessie_x86/Dockerfile
@@ -29,8 +29,8 @@
 
 FROM 32bit/debian:jessie
 
-RUN apt-get update && apt-get install -y curl git
+RUN apt-get update && apt-get install -y curl
 
 # Install nvm
 RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
\ No newline at end of file
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash
diff --git a/tools/dockerfile/distribtest/node_ubuntu1204_x64/Dockerfile b/tools/dockerfile/distribtest/node_ubuntu1204_x64/Dockerfile
index c53a4aa..0134dc9 100644
--- a/tools/dockerfile/distribtest/node_ubuntu1204_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/node_ubuntu1204_x64/Dockerfile
@@ -29,7 +29,7 @@
 
 FROM ubuntu:12.04
 
-RUN apt-get update && apt-get install -y curl git
+RUN apt-get update && apt-get install -y curl
 
 # Install nvm
 RUN touch .profile
diff --git a/tools/dockerfile/distribtest/node_ubuntu1404_x64/Dockerfile b/tools/dockerfile/distribtest/node_ubuntu1404_x64/Dockerfile
index 8fe6ae1..0fae447 100644
--- a/tools/dockerfile/distribtest/node_ubuntu1404_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/node_ubuntu1404_x64/Dockerfile
@@ -29,7 +29,7 @@
 
 FROM ubuntu:14.04
 
-RUN apt-get update && apt-get install -y curl git
+RUN apt-get update && apt-get install -y curl
 
 # Install nvm
 RUN touch .profile
diff --git a/tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile b/tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile
index 013c2a0..55da46c 100644
--- a/tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/node_ubuntu1504_x64/Dockerfile
@@ -29,7 +29,7 @@
 
 FROM ubuntu:15.04
 
-RUN apt-get update && apt-get install -y curl git
+RUN apt-get update && apt-get install -y curl
 
 # Install nvm
 RUN touch .profile
diff --git a/tools/dockerfile/distribtest/node_ubuntu1510_x64/Dockerfile b/tools/dockerfile/distribtest/node_ubuntu1510_x64/Dockerfile
index 43b3ae2..c050cab 100644
--- a/tools/dockerfile/distribtest/node_ubuntu1510_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/node_ubuntu1510_x64/Dockerfile
@@ -29,7 +29,7 @@
 
 FROM ubuntu:15.10
 
-RUN apt-get update && apt-get install -y curl git
+RUN apt-get update && apt-get install -y curl
 
 # Install nvm
 RUN touch .profile
diff --git a/tools/dockerfile/distribtest/node_ubuntu1604_x64/Dockerfile b/tools/dockerfile/distribtest/node_ubuntu1604_x64/Dockerfile
index 3eae754..ab9e8a3 100644
--- a/tools/dockerfile/distribtest/node_ubuntu1604_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/node_ubuntu1604_x64/Dockerfile
@@ -29,7 +29,7 @@
 
 FROM ubuntu:16.04
 
-RUN apt-get update && apt-get install -y curl git
+RUN apt-get update && apt-get install -y curl
 
 # Install nvm
 RUN touch .profile
diff --git a/tools/dockerfile/distribtest/python_arch_x64/Dockerfile b/tools/dockerfile/distribtest/python_arch_x64/Dockerfile
index 4d10e24..c4f2431 100644
--- a/tools/dockerfile/distribtest/python_arch_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_arch_x64/Dockerfile
@@ -30,7 +30,7 @@
 FROM base/archlinux
 
 RUN pacman --noconfirm -Syy
-RUN pacman --noconfirm -S git
-RUN pacman --noconfirm -S python
-RUN pacman --noconfirm -S python-pip
+RUN pacman --noconfirm -S openssl
+RUN pacman --noconfirm -S python2
+RUN pacman --noconfirm -S python2-pip
 
diff --git a/tools/dockerfile/distribtest/python_centos6_x64/Dockerfile b/tools/dockerfile/distribtest/python_centos6_x64/Dockerfile
index 683686c..79dae07 100644
--- a/tools/dockerfile/distribtest/python_centos6_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_centos6_x64/Dockerfile
@@ -29,9 +29,18 @@
 
 FROM centos:6
 
-RUN yum install -y git
-RUN yum install -y python
+RUN yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm
 
-RUN rpm -ivh http://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
-RUN yum install -y python-pip
+# Vanilla CentOS6 only has python 2.6 and we don't support that.
+RUN yum -y install yum -y install https://centos6.iuscommunity.org/ius-release.rpm
+RUN yum install -y python27
 
+# Override python2.6
+RUN ln -s /usr/bin/python2.7 /usr/local/bin/python
+RUN ln -s /usr/bin/python2.7 /usr/local/bin/python2
+
+# Install pip
+RUN curl https://bootstrap.pypa.io/get-pip.py | python -
+
+# "which" command required by python's run_distrib_test.sh
+RUN yum install -y which
diff --git a/tools/dockerfile/distribtest/python_centos7_x64/Dockerfile b/tools/dockerfile/distribtest/python_centos7_x64/Dockerfile
index 6b70f65..114957b 100644
--- a/tools/dockerfile/distribtest/python_centos7_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_centos7_x64/Dockerfile
@@ -29,7 +29,6 @@
 
 FROM centos:7
 
-RUN yum install -y git
 RUN yum install -y python
 RUN yum install -y epel-release
 RUN yum install -y python-pip
diff --git a/tools/dockerfile/distribtest/python_fedora20_x64/Dockerfile b/tools/dockerfile/distribtest/python_fedora20_x64/Dockerfile
index 1c91594..d580364 100644
--- a/tools/dockerfile/distribtest/python_fedora20_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_fedora20_x64/Dockerfile
@@ -29,9 +29,4 @@
 
 FROM fedora:20
 
-RUN yum clean all
-RUN yum update -y
-RUN yum install -y git
-RUN yum install -y python
-RUN yum install -y python-pip
-
+RUN yum clean all && yum update -y && yum install -y python python-pip
diff --git a/tools/dockerfile/distribtest/python_fedora21_x64/Dockerfile b/tools/dockerfile/distribtest/python_fedora21_x64/Dockerfile
index e35de10..b44fcff 100644
--- a/tools/dockerfile/distribtest/python_fedora21_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_fedora21_x64/Dockerfile
@@ -29,9 +29,4 @@
 
 FROM fedora:21
 
-RUN yum clean all
-RUN yum update -y
-RUN yum install -y git
-RUN yum install -y python
-RUN yum install -y python-pip
-
+RUN yum clean all && yum update -y && yum install -y python python-pip
diff --git a/tools/dockerfile/distribtest/python_fedora22_x64/Dockerfile b/tools/dockerfile/distribtest/python_fedora22_x64/Dockerfile
index 69c3b54..c641594 100644
--- a/tools/dockerfile/distribtest/python_fedora22_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_fedora22_x64/Dockerfile
@@ -29,9 +29,4 @@
 
 FROM fedora:22
 
-RUN yum clean all
-RUN yum update -y
-RUN yum install -y git
-RUN yum install -y python
-RUN yum install -y python-pip
-
+RUN yum clean all && yum update -y && yum install -y python python-pip
diff --git a/tools/dockerfile/distribtest/python_fedora23_x64/Dockerfile b/tools/dockerfile/distribtest/python_fedora23_x64/Dockerfile
index 74639a3..6c834d2 100644
--- a/tools/dockerfile/distribtest/python_fedora23_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_fedora23_x64/Dockerfile
@@ -29,9 +29,4 @@
 
 FROM fedora:23
 
-RUN yum clean all
-RUN yum update -y
-RUN yum install -y git
-RUN yum install -y python
-RUN yum install -y python-pip
-
+RUN yum clean all && yum update -y && yum install -y python python-pip
diff --git a/tools/dockerfile/distribtest/python_jessie_x64/Dockerfile b/tools/dockerfile/distribtest/python_jessie_x64/Dockerfile
index 3d511e2..5778d60 100644
--- a/tools/dockerfile/distribtest/python_jessie_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_jessie_x64/Dockerfile
@@ -29,6 +29,4 @@
 
 FROM debian:jessie
 
-RUN apt-get update
-RUN apt-get install -y git python python-pip
-
+RUN apt-get update && apt-get install -y python python-pip
diff --git a/tools/dockerfile/distribtest/python_jessie_x86/Dockerfile b/tools/dockerfile/distribtest/python_jessie_x86/Dockerfile
index 035d56b..e9cf991 100644
--- a/tools/dockerfile/distribtest/python_jessie_x86/Dockerfile
+++ b/tools/dockerfile/distribtest/python_jessie_x86/Dockerfile
@@ -29,6 +29,9 @@
 
 FROM 32bit/debian:jessie
 
-RUN apt-get update
-RUN apt-get install -y git python python-pip
+RUN apt-get update && apt-get install -y python python-pip
 
+# docker is running on a 64-bit machine, so we need to
+# override "uname -m" to report i686 instead of x86_64, otherwise
+# python will choose a wrong binary package to install.
+ENTRYPOINT ["linux32"]
diff --git a/tools/dockerfile/distribtest/python_opensuse_x64/Dockerfile b/tools/dockerfile/distribtest/python_opensuse_x64/Dockerfile
index 032beb9..ea5d4c7 100644
--- a/tools/dockerfile/distribtest/python_opensuse_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_opensuse_x64/Dockerfile
@@ -29,7 +29,12 @@
 
 FROM opensuse:42.1
 
-RUN zypper --non-interactive install git
 RUN zypper --non-interactive install python
 RUN zypper --non-interactive install python-pip
 
+# "which" command required by python's run_distrib_test.sh
+RUN zypper --non-interactive install which
+
+# Without this, pip won't be able to connect to
+# https://pypi.python.org/simple/
+RUN zypper --non-interactive install ca-certificates-mozilla
diff --git a/tools/dockerfile/distribtest/python_ubuntu1204_x64/Dockerfile b/tools/dockerfile/distribtest/python_ubuntu1204_x64/Dockerfile
index 9dbf90f..a48ce0e 100644
--- a/tools/dockerfile/distribtest/python_ubuntu1204_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_ubuntu1204_x64/Dockerfile
@@ -29,8 +29,4 @@
 
 FROM ubuntu:12.04
 
-RUN apt-get update -y
-RUN apt-get install -y git
-RUN apt-get install -y python
-RUN apt-get install -y python-pip
-
+RUN apt-get update -y && apt-get install -y python python-pip
diff --git a/tools/dockerfile/distribtest/python_ubuntu1404_x64/Dockerfile b/tools/dockerfile/distribtest/python_ubuntu1404_x64/Dockerfile
index 3b366a9..18dbfd4 100644
--- a/tools/dockerfile/distribtest/python_ubuntu1404_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_ubuntu1404_x64/Dockerfile
@@ -29,8 +29,4 @@
 
 FROM ubuntu:14.04
 
-RUN apt-get update -y
-RUN apt-get install -y git
-RUN apt-get install -y python
-RUN apt-get install -y python-pip
-
+RUN apt-get update -y && apt-get install -y python python-pip
diff --git a/tools/dockerfile/distribtest/python_ubuntu1504_x64/Dockerfile b/tools/dockerfile/distribtest/python_ubuntu1504_x64/Dockerfile
index de90b5b..444a54d 100644
--- a/tools/dockerfile/distribtest/python_ubuntu1504_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_ubuntu1504_x64/Dockerfile
@@ -29,8 +29,4 @@
 
 FROM ubuntu:15.04
 
-RUN apt-get update -y
-RUN apt-get install -y git
-RUN apt-get install -y python
-RUN apt-get install -y python-pip
-
+RUN apt-get update -y && apt-get install -y python python-pip
diff --git a/tools/dockerfile/distribtest/python_ubuntu1510_x64/Dockerfile b/tools/dockerfile/distribtest/python_ubuntu1510_x64/Dockerfile
index d10e04a..245ffb9 100644
--- a/tools/dockerfile/distribtest/python_ubuntu1510_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_ubuntu1510_x64/Dockerfile
@@ -29,8 +29,4 @@
 
 FROM ubuntu:15.10
 
-RUN apt-get update -y
-RUN apt-get install -y git
-RUN apt-get install -y python
-RUN apt-get install -y python-pip
-
+RUN apt-get update -y && apt-get install -y python python-pip
diff --git a/tools/dockerfile/distribtest/python_ubuntu1604_x64/Dockerfile b/tools/dockerfile/distribtest/python_ubuntu1604_x64/Dockerfile
index bc56285..a1ac305 100644
--- a/tools/dockerfile/distribtest/python_ubuntu1604_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_ubuntu1604_x64/Dockerfile
@@ -29,8 +29,4 @@
 
 FROM ubuntu:16.04
 
-RUN apt-get update -y
-RUN apt-get install -y git
-RUN apt-get install -y python
-RUN apt-get install -y python-pip
-
+RUN apt-get update -y && apt-get install -y python python-pip
diff --git a/tools/dockerfile/distribtest/python_wheezy_x64/Dockerfile b/tools/dockerfile/distribtest/python_wheezy_x64/Dockerfile
index 895dd96..46353b9 100644
--- a/tools/dockerfile/distribtest/python_wheezy_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/python_wheezy_x64/Dockerfile
@@ -29,6 +29,4 @@
 
 FROM debian:wheezy
 
-RUN apt-get update
-RUN apt-get install -y git python python-pip
-
+RUN apt-get update -y && apt-get install -y python python-pip
diff --git a/tools/dockerfile/distribtest/ruby_centos6_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_centos6_x64/Dockerfile
index 28a5c4a..fd2cf63 100644
--- a/tools/dockerfile/distribtest/ruby_centos6_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_centos6_x64/Dockerfile
@@ -29,6 +29,4 @@
 
 FROM centos:6
 
-RUN yum install -y git
 RUN yum install -y ruby
-
diff --git a/tools/dockerfile/distribtest/ruby_centos7_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_centos7_x64/Dockerfile
index bdc100e..5bb9bd6 100644
--- a/tools/dockerfile/distribtest/ruby_centos7_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_centos7_x64/Dockerfile
@@ -29,6 +29,4 @@
 
 FROM centos:7
 
-RUN yum install -y git
 RUN yum install -y ruby
-
diff --git a/tools/dockerfile/distribtest/ruby_fedora20_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_fedora20_x64/Dockerfile
index 50ff0b0..9f23be9 100644
--- a/tools/dockerfile/distribtest/ruby_fedora20_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_fedora20_x64/Dockerfile
@@ -29,8 +29,4 @@
 
 FROM fedora:20
 
-RUN yum clean all
-RUN yum update -y
-RUN yum install -y git
-RUN yum install -y ruby
-
+RUN yum clean all && yum update -y && yum install -y ruby
diff --git a/tools/dockerfile/distribtest/ruby_fedora21_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_fedora21_x64/Dockerfile
index 219ecc8..57106a4 100644
--- a/tools/dockerfile/distribtest/ruby_fedora21_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_fedora21_x64/Dockerfile
@@ -29,8 +29,4 @@
 
 FROM fedora:21
 
-RUN yum clean all
-RUN yum update -y
-RUN yum install -y git
-RUN yum install -y ruby
-
+RUN yum clean all && yum update -y && yum install -y ruby
diff --git a/tools/dockerfile/distribtest/ruby_fedora22_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_fedora22_x64/Dockerfile
index 49d4c7d..d770177 100644
--- a/tools/dockerfile/distribtest/ruby_fedora22_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_fedora22_x64/Dockerfile
@@ -29,8 +29,4 @@
 
 FROM fedora:22
 
-RUN yum clean all
-RUN yum update -y
-RUN yum install -y git
-RUN yum install -y ruby
-
+RUN yum clean all && yum update -y && yum install -y ruby
diff --git a/tools/dockerfile/distribtest/ruby_fedora23_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_fedora23_x64/Dockerfile
index 3c5363f..2c9b78e 100644
--- a/tools/dockerfile/distribtest/ruby_fedora23_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_fedora23_x64/Dockerfile
@@ -29,8 +29,4 @@
 
 FROM fedora:23
 
-RUN yum clean all
-RUN yum update -y
-RUN yum install -y git
-RUN yum install -y ruby
-
+RUN yum clean all && yum update -y && yum install -y ruby
diff --git a/tools/dockerfile/distribtest/ruby_jessie_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_jessie_x64/Dockerfile
index 6a3d7ed..4784bd7 100644
--- a/tools/dockerfile/distribtest/ruby_jessie_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_jessie_x64/Dockerfile
@@ -29,7 +29,4 @@
 
 FROM debian:jessie
 
-RUN apt-get update
-RUN apt-get install -y git
-RUN apt-get install -y ruby-full
-
+RUN apt-get update && apt-get install -y ruby-full
diff --git a/tools/dockerfile/distribtest/ruby_jessie_x86/Dockerfile b/tools/dockerfile/distribtest/ruby_jessie_x86/Dockerfile
index ca3b731..4f649cb 100644
--- a/tools/dockerfile/distribtest/ruby_jessie_x86/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_jessie_x86/Dockerfile
@@ -29,7 +29,4 @@
 
 FROM 32bit/debian:jessie
 
-RUN apt-get update
-RUN apt-get install -y git
-RUN apt-get install -y ruby-full
-
+RUN apt-get update && apt-get install -y ruby-full
diff --git a/tools/dockerfile/distribtest/ruby_opensuse_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_opensuse_x64/Dockerfile
index a942304..a249950 100644
--- a/tools/dockerfile/distribtest/ruby_opensuse_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_opensuse_x64/Dockerfile
@@ -29,6 +29,4 @@
 
 FROM opensuse:42.1
 
-RUN zypper --non-interactive install git
 RUN zypper --non-interactive install ruby
-
diff --git a/tools/dockerfile/distribtest/ruby_ubuntu1204_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_ubuntu1204_x64/Dockerfile
index 66f1710..95b7702 100644
--- a/tools/dockerfile/distribtest/ruby_ubuntu1204_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_ubuntu1204_x64/Dockerfile
@@ -29,7 +29,4 @@
 
 FROM ubuntu:12.04
 
-RUN apt-get update -y
-RUN apt-get install -y git
-RUN apt-get install -y ruby-full
-
+RUN apt-get update -y && apt-get install -y ruby-full
diff --git a/tools/dockerfile/distribtest/ruby_ubuntu1404_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_ubuntu1404_x64/Dockerfile
index dc533a5..66ba01d 100644
--- a/tools/dockerfile/distribtest/ruby_ubuntu1404_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_ubuntu1404_x64/Dockerfile
@@ -29,7 +29,4 @@
 
 FROM ubuntu:14.04
 
-RUN apt-get update -y
-RUN apt-get install -y git
-RUN apt-get install -y ruby-full
-
+RUN apt-get update -y && apt-get install -y ruby-full
diff --git a/tools/dockerfile/distribtest/ruby_ubuntu1504_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_ubuntu1504_x64/Dockerfile
index 7e4f203..81e7ca1 100644
--- a/tools/dockerfile/distribtest/ruby_ubuntu1504_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_ubuntu1504_x64/Dockerfile
@@ -29,7 +29,4 @@
 
 FROM ubuntu:15.04
 
-RUN apt-get update -y
-RUN apt-get install -y git
-RUN apt-get install -y ruby-full
-
+RUN apt-get update -y && apt-get install -y ruby-full
diff --git a/tools/dockerfile/distribtest/ruby_ubuntu1510_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_ubuntu1510_x64/Dockerfile
index 43ef63e..37b897f 100644
--- a/tools/dockerfile/distribtest/ruby_ubuntu1510_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_ubuntu1510_x64/Dockerfile
@@ -29,7 +29,4 @@
 
 FROM ubuntu:15.10
 
-RUN apt-get update -y
-RUN apt-get install -y git
-RUN apt-get install -y ruby-full
-
+RUN apt-get update -y && apt-get install -y ruby-full
diff --git a/tools/dockerfile/distribtest/ruby_ubuntu1604_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_ubuntu1604_x64/Dockerfile
index 3b63976..5c54b8f 100644
--- a/tools/dockerfile/distribtest/ruby_ubuntu1604_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_ubuntu1604_x64/Dockerfile
@@ -29,7 +29,4 @@
 
 FROM ubuntu:16.04
 
-RUN apt-get update -y
-RUN apt-get install -y git
-RUN apt-get install -y ruby-full
-
+RUN apt-get update -y && apt-get install -y ruby-full
diff --git a/tools/dockerfile/distribtest/ruby_wheezy_x64/Dockerfile b/tools/dockerfile/distribtest/ruby_wheezy_x64/Dockerfile
index 1ff083d..2e6593c 100644
--- a/tools/dockerfile/distribtest/ruby_wheezy_x64/Dockerfile
+++ b/tools/dockerfile/distribtest/ruby_wheezy_x64/Dockerfile
@@ -29,7 +29,4 @@
 
 FROM debian:wheezy
 
-RUN apt-get update
-RUN apt-get install -y git
-RUN apt-get install -y ruby-full
-
+RUN apt-get update && apt-get install -y ruby-full
diff --git a/tools/dockerfile/grpc_tests_multilang_x86/Dockerfile b/tools/dockerfile/grpc_tests_multilang_x86/Dockerfile
deleted file mode 100644
index 6e0dbd7..0000000
--- a/tools/dockerfile/grpc_tests_multilang_x86/Dockerfile
+++ /dev/null
@@ -1,162 +0,0 @@
-# Copyright 2015-2016, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# Dockerfile for running gRPC test suites inside a docker container.
-
-FROM 32bit/debian:jessie
-
-# Install Git and basic packages.
-RUN apt-get update && apt-get install -y \
-  autoconf \
-  autotools-dev \
-  build-essential \
-  bzip2 \
-  ccache \
-  curl \
-  gcc \
-  gcc-multilib \
-  git \
-  golang \
-  gyp \
-  lcov \
-  libc6 \
-  libc6-dbg \
-  libc6-dev \
-  libgtest-dev \
-  libtool \
-  make \
-  perl \
-  strace \
-  python-dev \
-  python-setuptools \
-  python-yaml \
-  telnet \
-  unzip \
-  wget \
-  zip && apt-get clean
-
-# Prepare ccache
-RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
-RUN ln -s /usr/bin/ccache /usr/local/bin/g++
-RUN ln -s /usr/bin/ccache /usr/local/bin/cc
-RUN ln -s /usr/bin/ccache /usr/local/bin/c++
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
-
-##################
-# C++ dependencies
-RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang
-
-#################
-# C# dependencies
-
-# Update to a newer version of mono
-RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-RUN echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list
-
-# Install dependencies
-RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
-    mono-devel \
-    nunit \
-    nunit-console \
-    monodevelop
-
-# Download NuGet
-RUN cd /var/local && wget www.nuget.org/NuGet.exe
-ENV NUGET mono /var/local/NuGet.exe
-
-##################
-# Node dependencies
-
-# Install nvm
-RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
-RUN /bin/bash -l -c "nvm install 0.12 && npm config set cache /tmp/npm-cache"
-
-##################
-# Ruby dependencies
-
-# Install rvm
-RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
-RUN \curl -sSL https://get.rvm.io | bash -s stable
-
-# Install Ruby 2.1
-RUN /bin/bash -l -c "rvm install ruby-2.1"
-RUN /bin/bash -l -c "rvm use --default ruby-2.1"
-RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
-RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
-RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
-RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
-
-##################
-# Python dependencies
-
-# Install dependencies
-
-RUN apt-get update && apt-get install -y \
-    python-all-dev \
-    python3-all-dev \
-    python-pip \
-    python-virtualenv
-
-# Install Python packages from PyPI
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2
-
-# For sanity test
-RUN pip install simplejson mako
-
-##################
-# PHP dependencies
-
-# Install dependencies
-
-RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
-
-RUN apt-get update && apt-get install -y \
-    git php5 php5-dev phpunit unzip
-
-##################
-# Zookeeper dependencies
-RUN apt-get install -y libzookeeper-mt-dev
-
-##################
-# Build profiling
-RUN apt-get install -y time
-
-RUN mkdir /var/local/jenkins
-
-# Define the default command.
-CMD ["bash"]
diff --git a/tools/dockerfile/grpc_tests_multilang_x64/Dockerfile b/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
similarity index 60%
rename from tools/dockerfile/grpc_tests_multilang_x64/Dockerfile
rename to tools/dockerfile/test/csharp_jessie_x64/Dockerfile
index aa5fc5c..0052de6 100644
--- a/tools/dockerfile/grpc_tests_multilang_x64/Dockerfile
+++ b/tools/dockerfile/test/csharp_jessie_x64/Dockerfile
@@ -27,8 +27,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Dockerfile for running gRPC test suites inside a docker container.
-
 FROM debian:jessie
 
 # Install Git and basic packages.
@@ -61,19 +59,11 @@
   wget \
   zip && apt-get clean
 
-# Prepare ccache
-RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
-RUN ln -s /usr/bin/ccache /usr/local/bin/g++
-RUN ln -s /usr/bin/ccache /usr/local/bin/cc
-RUN ln -s /usr/bin/ccache /usr/local/bin/c++
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang
-RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
 
-##################
-# C++ dependencies
-RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang
-
-#################
+#================
 # C# dependencies
 
 # Update to a newer version of mono
@@ -86,77 +76,23 @@
 # Install dependencies
 RUN apt-get update && apt-get -y dist-upgrade && apt-get install -y \
     mono-devel \
-    nunit \
-    nunit-console \
-    monodevelop
+    ca-certificates-mono \
+    nuget \
+    && apt-get clean
 
-# Download NuGet
-RUN cd /var/local && wget www.nuget.org/NuGet.exe
-ENV NUGET mono /var/local/NuGet.exe
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
 
-##################
-# Node dependencies
-
-# Install nvm
-RUN touch .profile
-RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
-RUN /bin/bash -l -c "nvm install 0.12 && npm config set cache /tmp/npm-cache"
-
-##################
-# Ruby dependencies
-
-# Install rvm
-RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
-RUN \curl -sSL https://get.rvm.io | bash -s stable
-
-# Install Ruby 2.1
-RUN /bin/bash -l -c "rvm install ruby-2.1"
-RUN /bin/bash -l -c "rvm use --default ruby-2.1"
-RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
-RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
-RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
-RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
-
-##################
-# Python dependencies
-
-# Install dependencies
-
-RUN apt-get update && apt-get install -y \
-    python-all-dev \
-    python3-all-dev \
-    python-pip
-
-# Install Python packages from PyPI
-RUN pip install pip --upgrade
-RUN pip install virtualenv
-RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 tox
-
-# For sanity test
-RUN pip install simplejson mako
-
-##################
-# PHP dependencies
-
-# Install dependencies
-
-RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' \
-    >> /etc/apt/sources.list.d/dotdeb.list"
-RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
-
-RUN apt-get update && apt-get install -y \
-    git php5 php5-dev phpunit unzip
-
-##################
+#======================
 # Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
 RUN apt-get install -y libzookeeper-mt-dev
 
-##################
-# Build profiling
-RUN apt-get install -y time
-
 RUN mkdir /var/local/jenkins
 
 # Define the default command.
diff --git a/tools/dockerfile/grpc_sanity/Dockerfile b/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
similarity index 75%
copy from tools/dockerfile/grpc_sanity/Dockerfile
copy to tools/dockerfile/test/cxx_jessie_x64/Dockerfile
index 8833141..e3ed39d 100644
--- a/tools/dockerfile/grpc_sanity/Dockerfile
+++ b/tools/dockerfile/test/cxx_jessie_x64/Dockerfile
@@ -27,8 +27,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Dockerfile for running gRPC sanity tests
-
 FROM debian:jessie
 
 # Install Git and basic packages.
@@ -61,21 +59,26 @@
   wget \
   zip && apt-get clean
 
-##################
-# Sanity test dependencies
-RUN apt-get update && apt-get install -y python-pip
-RUN pip install simplejson mako
-
-##################
-# Docker "inception".
-# Note this is quite the ugly hack.
-# This makes sure that the docker binary we inject has its dependencies.
-RUN curl https://get.docker.com/ | sh
-RUN apt-get remove --purge -y docker-engine
-
-##################
+#================
 # Build profiling
-RUN apt-get install -y time
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#=================
+# C++ dependencies
+RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
 
 RUN mkdir /var/local/jenkins
 
diff --git a/tools/dockerfile/grpc_sanity/Dockerfile b/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
similarity index 74%
copy from tools/dockerfile/grpc_sanity/Dockerfile
copy to tools/dockerfile/test/cxx_jessie_x86/Dockerfile
index 8833141..9a8f2b1 100644
--- a/tools/dockerfile/grpc_sanity/Dockerfile
+++ b/tools/dockerfile/test/cxx_jessie_x86/Dockerfile
@@ -27,9 +27,7 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Dockerfile for running gRPC sanity tests
-
-FROM debian:jessie
+FROM 32bit/debian:jessie
 
 # Install Git and basic packages.
 RUN apt-get update && apt-get install -y \
@@ -61,21 +59,26 @@
   wget \
   zip && apt-get clean
 
-##################
-# Sanity test dependencies
-RUN apt-get update && apt-get install -y python-pip
-RUN pip install simplejson mako
-
-##################
-# Docker "inception".
-# Note this is quite the ugly hack.
-# This makes sure that the docker binary we inject has its dependencies.
-RUN curl https://get.docker.com/ | sh
-RUN apt-get remove --purge -y docker-engine
-
-##################
+#================
 # Build profiling
-RUN apt-get install -y time
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#=================
+# C++ dependencies
+RUN apt-get update && apt-get -y install libgflags-dev libgtest-dev libc++-dev clang && apt-get clean
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
 
 RUN mkdir /var/local/jenkins
 
diff --git a/tools/dockerfile/grpc_sanity/Dockerfile b/tools/dockerfile/test/node_jessie_x64/Dockerfile
similarity index 73%
copy from tools/dockerfile/grpc_sanity/Dockerfile
copy to tools/dockerfile/test/node_jessie_x64/Dockerfile
index 8833141..0655bf7 100644
--- a/tools/dockerfile/grpc_sanity/Dockerfile
+++ b/tools/dockerfile/test/node_jessie_x64/Dockerfile
@@ -27,8 +27,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Dockerfile for running gRPC sanity tests
-
 FROM debian:jessie
 
 # Install Git and basic packages.
@@ -61,21 +59,30 @@
   wget \
   zip && apt-get clean
 
-##################
-# Sanity test dependencies
-RUN apt-get update && apt-get install -y python-pip
-RUN pip install simplejson mako
-
-##################
-# Docker "inception".
-# Note this is quite the ugly hack.
-# This makes sure that the docker binary we inject has its dependencies.
-RUN curl https://get.docker.com/ | sh
-RUN apt-get remove --purge -y docker-engine
-
-##################
+#================
 # Build profiling
-RUN apt-get install -y time
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#==================
+# Node dependencies
+
+# Install nvm
+RUN touch .profile
+RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.25.4/install.sh | bash
+RUN /bin/bash -l -c "nvm install 0.12 && npm config set cache /tmp/npm-cache"
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
 
 RUN mkdir /var/local/jenkins
 
diff --git a/tools/dockerfile/grpc_sanity/Dockerfile b/tools/dockerfile/test/php_jessie_x64/Dockerfile
similarity index 68%
copy from tools/dockerfile/grpc_sanity/Dockerfile
copy to tools/dockerfile/test/php_jessie_x64/Dockerfile
index 8833141..43081e7 100644
--- a/tools/dockerfile/grpc_sanity/Dockerfile
+++ b/tools/dockerfile/test/php_jessie_x64/Dockerfile
@@ -27,8 +27,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Dockerfile for running gRPC sanity tests
-
 FROM debian:jessie
 
 # Install Git and basic packages.
@@ -61,21 +59,36 @@
   wget \
   zip && apt-get clean
 
-##################
-# Sanity test dependencies
-RUN apt-get update && apt-get install -y python-pip
-RUN pip install simplejson mako
-
-##################
-# Docker "inception".
-# Note this is quite the ugly hack.
-# This makes sure that the docker binary we inject has its dependencies.
-RUN curl https://get.docker.com/ | sh
-RUN apt-get remove --purge -y docker-engine
-
-##################
+#================
 # Build profiling
-RUN apt-get install -y time
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#=================
+# PHP dependencies
+
+# Install dependencies
+
+RUN /bin/bash -l -c "echo 'deb http://packages.dotdeb.org wheezy-php55 all' \
+    >> /etc/apt/sources.list.d/dotdeb.list"
+RUN /bin/bash -l -c "echo 'deb-src http://packages.dotdeb.org wheezy-php55 all' \
+    >> /etc/apt/sources.list.d/dotdeb.list"
+RUN wget http://www.dotdeb.org/dotdeb.gpg -O- | apt-key add -
+
+RUN apt-get update && apt-get install -y \
+    git php5 php5-dev phpunit unzip
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
 
 RUN mkdir /var/local/jenkins
 
diff --git a/tools/dockerfile/grpc_sanity/Dockerfile b/tools/dockerfile/test/python_jessie_x64/Dockerfile
similarity index 70%
copy from tools/dockerfile/grpc_sanity/Dockerfile
copy to tools/dockerfile/test/python_jessie_x64/Dockerfile
index 8833141..7ed8b4c 100644
--- a/tools/dockerfile/grpc_sanity/Dockerfile
+++ b/tools/dockerfile/test/python_jessie_x64/Dockerfile
@@ -27,8 +27,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Dockerfile for running gRPC sanity tests
-
 FROM debian:jessie
 
 # Install Git and basic packages.
@@ -61,21 +59,37 @@
   wget \
   zip && apt-get clean
 
-##################
-# Sanity test dependencies
-RUN apt-get update && apt-get install -y python-pip
-RUN pip install simplejson mako
-
-##################
-# Docker "inception".
-# Note this is quite the ugly hack.
-# This makes sure that the docker binary we inject has its dependencies.
-RUN curl https://get.docker.com/ | sh
-RUN apt-get remove --purge -y docker-engine
-
-##################
+#================
 # Build profiling
-RUN apt-get install -y time
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#====================
+# Python dependencies
+
+# Install dependencies
+
+RUN apt-get update && apt-get install -y \
+    python-all-dev \
+    python3-all-dev \
+    python-pip
+
+# Install Python packages from PyPI
+RUN pip install pip --upgrade
+RUN pip install virtualenv
+RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.0.0a2 tox
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
 
 RUN mkdir /var/local/jenkins
 
diff --git a/tools/dockerfile/grpc_sanity/Dockerfile b/tools/dockerfile/test/ruby_jessie_x64/Dockerfile
similarity index 65%
copy from tools/dockerfile/grpc_sanity/Dockerfile
copy to tools/dockerfile/test/ruby_jessie_x64/Dockerfile
index 8833141..91af772 100644
--- a/tools/dockerfile/grpc_sanity/Dockerfile
+++ b/tools/dockerfile/test/ruby_jessie_x64/Dockerfile
@@ -27,8 +27,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Dockerfile for running gRPC sanity tests
-
 FROM debian:jessie
 
 # Install Git and basic packages.
@@ -61,21 +59,37 @@
   wget \
   zip && apt-get clean
 
-##################
-# Sanity test dependencies
-RUN apt-get update && apt-get install -y python-pip
-RUN pip install simplejson mako
-
-##################
-# Docker "inception".
-# Note this is quite the ugly hack.
-# This makes sure that the docker binary we inject has its dependencies.
-RUN curl https://get.docker.com/ | sh
-RUN apt-get remove --purge -y docker-engine
-
-##################
+#================
 # Build profiling
-RUN apt-get install -y time
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#==================
+# Ruby dependencies
+
+# Install rvm
+RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
+RUN \curl -sSL https://get.rvm.io | bash -s stable
+
+# Install Ruby 2.1
+RUN /bin/bash -l -c "rvm install ruby-2.1"
+RUN /bin/bash -l -c "rvm use --default ruby-2.1"
+RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
+RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc"
+RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc"
+RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc"
+
+# Prepare ccache
+RUN ln -s /usr/bin/ccache /usr/local/bin/gcc
+RUN ln -s /usr/bin/ccache /usr/local/bin/g++
+RUN ln -s /usr/bin/ccache /usr/local/bin/cc
+RUN ln -s /usr/bin/ccache /usr/local/bin/c++
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang
+RUN ln -s /usr/bin/ccache /usr/local/bin/clang++
+
+#======================
+# Zookeeper dependencies
+# TODO(jtattermusch): is zookeeper still needed?
+RUN apt-get install -y libzookeeper-mt-dev
 
 RUN mkdir /var/local/jenkins
 
diff --git a/tools/dockerfile/grpc_sanity/Dockerfile b/tools/dockerfile/test/sanity/Dockerfile
similarity index 93%
rename from tools/dockerfile/grpc_sanity/Dockerfile
rename to tools/dockerfile/test/sanity/Dockerfile
index 8833141..51ee49b 100644
--- a/tools/dockerfile/grpc_sanity/Dockerfile
+++ b/tools/dockerfile/test/sanity/Dockerfile
@@ -27,8 +27,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-# Dockerfile for running gRPC sanity tests
-
 FROM debian:jessie
 
 # Install Git and basic packages.
@@ -61,22 +59,22 @@
   wget \
   zip && apt-get clean
 
-##################
+#================
+# Build profiling
+RUN apt-get update && apt-get install -y time && apt-get clean
+
+#========================
 # Sanity test dependencies
 RUN apt-get update && apt-get install -y python-pip
 RUN pip install simplejson mako
 
-##################
-# Docker "inception".
+#===================
+# Docker "inception"
 # Note this is quite the ugly hack.
 # This makes sure that the docker binary we inject has its dependencies.
 RUN curl https://get.docker.com/ | sh
 RUN apt-get remove --purge -y docker-engine
 
-##################
-# Build profiling
-RUN apt-get install -y time
-
 RUN mkdir /var/local/jenkins
 
 # Define the default command.
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index cdb998d..5de1a15 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.13.0.0
+PROJECT_NUMBER         = 0.14.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 558ec9d..bd724d8 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.13.0.0
+PROJECT_NUMBER         = 0.14.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index a3b4581..e00fcfc 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.13.0.0
+PROJECT_NUMBER         = 0.14.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index e91b47c..c7b5be7 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -40,7 +40,7 @@
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.13.0.0
+PROJECT_NUMBER         = 0.14.0-dev
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/jenkins/build_and_run_docker.sh b/tools/jenkins/build_and_run_docker.sh
index b77cd0a..92dbbc6 100755
--- a/tools/jenkins/build_and_run_docker.sh
+++ b/tools/jenkins/build_and_run_docker.sh
@@ -37,9 +37,6 @@
 git_root=$(pwd)
 cd -
 
-# Create a local branch so the child Docker script won't complain
-git branch -f jenkins-docker
-
 # Inputs
 # DOCKERFILE_DIR - Directory in which Dockerfile file is located.
 # DOCKER_RUN_SCRIPT - Script to run under docker (relative to grpc repo root)
diff --git a/tools/jenkins/build_artifacts.sh b/tools/jenkins/build_artifacts.sh
index 9af553a..c0acbdf 100755
--- a/tools/jenkins/build_artifacts.sh
+++ b/tools/jenkins/build_artifacts.sh
@@ -39,4 +39,8 @@
 curr_platform="$platform"
 unset platform  # variable named 'platform' breaks the windows build
 
-python tools/run_tests/task_runner.py -f artifact $language $curr_platform $architecture
+if [ "$curr_platform" == "linux" ] && [ "$language" == "ruby" ] ; then
+  ./tools/run_tests/build_artifact_ruby.sh
+else
+  python tools/run_tests/task_runner.py -f artifact $language $curr_platform $architecture
+fi
diff --git a/tools/jenkins/build_docker_and_run_tests.sh b/tools/jenkins/build_docker_and_run_tests.sh
index 58163bb..e2ac751 100755
--- a/tools/jenkins/build_docker_and_run_tests.sh
+++ b/tools/jenkins/build_docker_and_run_tests.sh
@@ -33,8 +33,8 @@
 
 set -ex
 
-cd `dirname $0`/../..
-git_root=`pwd`
+cd $(dirname $0)/../..
+git_root=$(pwd)
 cd -
 
 # Ensure existence of ccache directory
diff --git a/tools/jenkins/docker_run.sh b/tools/jenkins/docker_run.sh
index 49553aa..519dc5c 100755
--- a/tools/jenkins/docker_run.sh
+++ b/tools/jenkins/docker_run.sh
@@ -31,18 +31,24 @@
 # This script is invoked by build_docker_* inside a docker
 # container. You should never need to call this script on your own.
 
-set -e
+set -ex
 
-mkdir -p /var/local/git
-git clone --recursive "$EXTERNAL_GIT_ROOT" /var/local/git/grpc
+if [ "$RELATIVE_COPY_PATH" == "" ]
+then
+  mkdir -p /var/local/git
+  git clone --recursive "$EXTERNAL_GIT_ROOT" /var/local/git/grpc
+else
+  mkdir -p "/var/local/git/grpc/$RELATIVE_COPY_PATH"
+  cp -r "$EXTERNAL_GIT_ROOT/$RELATIVE_COPY_PATH"/* "/var/local/git/grpc/$RELATIVE_COPY_PATH"
+fi
 
 if [ -x "$(command -v rvm)" ]
 then
   rvm use ruby-2.1
 fi
 
-cd /var/local/git/grpc
-
 nvm use 4 || true
 
+cd /var/local/git/grpc
+
 $RUN_COMMAND
diff --git a/tools/jenkins/docker_run_tests.sh b/tools/jenkins/docker_run_tests.sh
index 26e5585..282b857 100755
--- a/tools/jenkins/docker_run_tests.sh
+++ b/tools/jenkins/docker_run_tests.sh
@@ -38,18 +38,11 @@
 
 # Ensure that programs depending on current-user-ownership of cache directories
 # are satisfied (it's being mounted from outside the image).
-chown `whoami` $XDG_CACHE_HOME
+chown $(whoami) $XDG_CACHE_HOME
 
 mkdir -p /var/local/git
 git clone --recursive /var/local/jenkins/grpc /var/local/git/grpc
 
-nvm use 0.12 || true
-
-if [ -x "$(command -v rvm)" ]
-then
-  rvm use ruby-2.1
-fi
-
 mkdir -p reports
 
 exit_code=0
diff --git a/tools/run_tests/build_artifact_python.sh b/tools/run_tests/build_artifact_python.sh
index 48cf390..835fad8 100755
--- a/tools/run_tests/build_artifact_python.sh
+++ b/tools/run_tests/build_artifact_python.sh
@@ -39,11 +39,13 @@
   pip install -rrequirements.txt
 fi
 
-GRPC_PYTHON_BUILD_WITH_CYTHON=1 ${SETARCH_CMD} python setup.py \
-    bdist_wheel \
-    sdist \
+GRPC_PYTHON_USE_CUSTOM_BDIST=0  \
+GRPC_PYTHON_BUILD_WITH_CYTHON=1 \
+${SETARCH_CMD} python setup.py  \
+    bdist_wheel                 \
+    sdist                       \
     bdist_egg_grpc_custom
 
 mkdir -p artifacts
 
-cp -r dist/* artifacts
\ No newline at end of file
+cp -r dist/* artifacts
diff --git a/tools/run_tests/build_artifact_ruby.sh b/tools/run_tests/build_artifact_ruby.sh
index 482d128..2d97b40 100755
--- a/tools/run_tests/build_artifact_ruby.sh
+++ b/tools/run_tests/build_artifact_ruby.sh
@@ -27,16 +27,40 @@
 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
 set -ex
 
+SYSTEM=`uname | cut -f 1 -d_`
+
 cd $(dirname $0)/../..
+set +ex
+[[ -s /etc/profile.d/rvm.sh ]] && . /etc/profile.d/rvm.sh
+[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
+set -ex
 
-${SETARCH_CMD} bundle install
+if [ "$SYSTEM" == "MSYS" ] ; then
+  SYSTEM=MINGW32
+fi
+if [ "$SYSTEM" == "MINGW64" ] ; then
+  SYSTEM=MINGW32
+fi
 
-${SETARCH_CMD} rake native gem
+if [ "$SYSTEM" == "MINGW32" ] ; then
+  echo "Need Linux to build the Windows ruby gem."
+  exit 1
+fi
+
+set +ex
+rvm use default
+gem install bundler --update
+bundle install
+set -ex
+
+rake gem:native
+
+if [ "$SYSTEM" == "Darwin" ] ; then
+  rm `ls pkg/*.gem | grep -v darwin`
+fi
 
 mkdir -p artifacts
 
 cp pkg/*.gem artifacts
-
diff --git a/tools/run_tests/build_node.sh b/tools/run_tests/build_node.sh
index 8f2ab44..9c4af07 100755
--- a/tools/run_tests/build_node.sh
+++ b/tools/run_tests/build_node.sh
@@ -29,8 +29,12 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+NODE_VERSION=$1
+source ~/.nvm/nvm.sh
 set -ex
 
+nvm use $NODE_VERSION
+
 CONFIG=${CONFIG:-opt}
 
 # change to grpc repo root
diff --git a/tools/run_tests/build_package_python.sh b/tools/run_tests/build_package_python.sh
new file mode 100755
index 0000000..2511a6a
--- /dev/null
+++ b/tools/run_tests/build_package_python.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set -ex
+
+cd $(dirname $0)/../..
+
+mkdir -p artifacts/
+
+# All the python packages have been built in the artifact phase already
+# and we only collect them here to deliver them to the distribtest phase.
+cp -r $EXTERNAL_GIT_ROOT/architecture={x86,x64},language=python,platform={windows,linux,macos}/artifacts/* artifacts/ || true
+
+# TODO: all the artifact builder configurations generate a grpcio-VERSION.tar.gz
+# source distribution package, and only one of them will end up
+# in the artifacts/ directory. They should be all equivalent though.
diff --git a/tools/run_tests/build_package_ruby.sh b/tools/run_tests/build_package_ruby.sh
new file mode 100755
index 0000000..1a5b943
--- /dev/null
+++ b/tools/run_tests/build_package_ruby.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Copyright 2016, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set -ex
+
+cd $(dirname $0)/../..
+
+mkdir -p artifacts/
+
+# All the ruby packages have been built in the artifact phase already
+# and we only collect them here to deliver them to the distribtest phase.
+cp -r $EXTERNAL_GIT_ROOT/architecture={x86,x64},language=ruby,platform={windows,linux,macos}/artifacts/* artifacts/ || true
+
+# TODO: all the artifact builder configurations generate a grpc-VERSION.gem
+# source distribution package, and only one of them will end up
+# in the artifacts/ directory. They should be all equivalent though.
diff --git a/tools/run_tests/distribtest_targets.py b/tools/run_tests/distribtest_targets.py
index e9a80d2..d0efdc0 100644
--- a/tools/run_tests/distribtest_targets.py
+++ b/tools/run_tests/distribtest_targets.py
@@ -38,6 +38,7 @@
   """Creates jobspec for a task running under docker."""
   environ = environ.copy()
   environ['RUN_COMMAND'] = shell_command
+  environ['RELATIVE_COPY_PATH'] = 'test/distrib'
 
   docker_args=[]
   for k,v in environ.iteritems():
@@ -54,28 +55,49 @@
   return jobspec
 
 
+def create_jobspec(name, cmdline, environ=None, shell=False,
+                   flake_retries=0, timeout_retries=0):
+  """Creates jobspec."""
+  jobspec = jobset.JobSpec(
+          cmdline=cmdline,
+          environ=environ,
+          shortname='distribtest.%s' % (name),
+          timeout_seconds=10*60,
+          flake_retries=flake_retries,
+          timeout_retries=timeout_retries,
+          shell=shell)
+  return jobspec
+
+
 class CSharpDistribTest(object):
   """Tests C# NuGet package"""
 
-  def __init__(self, platform, arch, docker_suffix):
-    self.name = 'csharp_nuget_%s_%s_%s' % (platform, arch, docker_suffix)
+  def __init__(self, platform, arch, docker_suffix=None):
+    self.name = 'csharp_nuget_%s_%s' % (platform, arch)
     self.platform = platform
     self.arch = arch
     self.docker_suffix = docker_suffix
-    self.labels = ['distribtest', 'csharp', platform, arch, docker_suffix]
+    self.labels = ['distribtest', 'csharp', platform, arch]
+    if docker_suffix:
+      self.name += '_%s' % docker_suffix
+      self.labels.append(docker_suffix)
 
   def pre_build_jobspecs(self):
     return []
 
   def build_jobspec(self):
-    if not self.platform == 'linux':
-      raise Exception("Not supported yet.")
-
-    return create_docker_jobspec(self.name,
+    if self.platform == 'linux':
+      return create_docker_jobspec(self.name,
           'tools/dockerfile/distribtest/csharp_%s_%s' % (
               self.docker_suffix,
               self.arch),
           'test/distrib/csharp/run_distrib_test.sh')
+    elif self.platform == 'macos':
+      return create_jobspec(self.name,
+          ['test/distrib/csharp/run_distrib_test.sh'],
+          environ={'EXTERNAL_GIT_ROOT': '../../..'})
+    else:
+      raise Exception("Not supported yet.")
 
   def __str__(self):
     return self.name
@@ -84,29 +106,35 @@
   """Tests Node package"""
 
   def __init__(self, platform, arch, docker_suffix, node_version):
-    self.name = 'node_npm_%s_%s_%s_%s' % (platform, arch,
-                                          docker_suffix, node_version)
+    self.name = 'node_npm_%s_%s_%s' % (platform, arch, node_version)
     self.platform = platform
     self.arch = arch
-    self.docker_suffix = docker_suffix
     self.node_version = node_version
     self.labels = ['distribtest', 'node', platform, arch,
                    docker_suffix, 'node-%s' % node_version]
+    if docker_suffix is not None:
+      self.name += '_%s' % docker_suffix
+      self.docker_suffix = docker_suffix
 
   def pre_build_jobspecs(self):
     return []
 
   def build_jobspec(self):
-    if self.platform not in ('linux',):
+    if self.platform == 'linux':
+      return create_docker_jobspec(self.name,
+                                   'tools/dockerfile/distribtest/node_%s_%s' % (
+                                       self.docker_suffix,
+                                       self.arch),
+                                   'test/distrib/node/run_distrib_test.sh %s' % (
+                                       self.node_version))
+    elif self.platform == 'macos':
+      return create_jobspec(self.name,
+                            ['test/distrib/node/run_distrib_test.sh',
+                             str(self.node_version)],
+                            environ={'EXTERNAL_GIT_ROOT': '../../..'})
+    else:
       raise Exception("Not supported yet.")
 
-    return create_docker_jobspec(self.name,
-                                 'tools/dockerfile/distribtest/node_%s_%s' % (
-                                     self.docker_suffix,
-                                     self.arch),
-                                 # bash -l needed to make nvm available
-                                 'bash -l test/distrib/node/run_distrib_test.sh %s' % (
-                                     self.node_version))
     def __str__(self):
       return self.name
 
@@ -175,6 +203,7 @@
           CSharpDistribTest('linux', 'x64', 'ubuntu1504'),
           CSharpDistribTest('linux', 'x64', 'ubuntu1510'),
           CSharpDistribTest('linux', 'x64', 'ubuntu1604'),
+          CSharpDistribTest('macos', 'x86'),
           PythonDistribTest('linux', 'x64', 'wheezy'),
           PythonDistribTest('linux', 'x64', 'jessie'),
           PythonDistribTest('linux', 'x86', 'jessie'),
@@ -206,6 +235,11 @@
           RubyDistribTest('linux', 'x64', 'ubuntu1504'),
           RubyDistribTest('linux', 'x64', 'ubuntu1510'),
           RubyDistribTest('linux', 'x64', 'ubuntu1604'),
+          NodeDistribTest('macos', 'x64', None, '0.10'),
+          NodeDistribTest('macos', 'x64', None, '0.12'),
+          NodeDistribTest('macos', 'x64', None, '3'),
+          NodeDistribTest('macos', 'x64', None, '4'),
+          NodeDistribTest('macos', 'x64', None, '5'),
           NodeDistribTest('linux', 'x86', 'jessie', '4')
           ] + [
             NodeDistribTest('linux', 'x64', os, version)
diff --git a/tools/run_tests/interop_html_report.template b/tools/run_tests/interop_html_report.template
index 114a508..46cce42 100644
--- a/tools/run_tests/interop_html_report.template
+++ b/tools/run_tests/interop_html_report.template
@@ -64,17 +64,8 @@
   % endif
 </%def>
 
-% if num_failures > 1:
-  <p><h2><font color="red">${num_failures} tests failed!</font></h2></p>
-% elif num_failures:
-  <p><h2><font color="red">${num_failures} test failed!</font></h2></p>
-% else:
-  <p><h2><font color="green">All tests passed!</font></h2></p>
-% endif
-
-% if cloud_to_prod:
+<%def name="display_cloud_to_prod_result(prod_server)">
   ## Each column header is the client language.
-  <h2>Cloud to Prod</h2>
   <table style="width:100%" border="1">
   <tr bgcolor="#00BFFF">
   <th>Client languages &#9658;<br/>Test Cases &#9660;</th>
@@ -87,15 +78,32 @@
     % for client_lang in client_langs:
       <% 
         if test_case in auth_test_cases:
-          shortname = 'cloud_to_prod_auth:%s:%s' % (client_lang, test_case)
+          shortname = 'cloud_to_prod_auth:%s:%s:%s' % (
+              prod_server, client_lang, test_case)
         else:
-          shortname = 'cloud_to_prod:%s:%s' % (client_lang, test_case)
+          shortname = 'cloud_to_prod:%s:%s:%s' % (
+              prod_server, client_lang, test_case)
       %>
       ${fill_one_test_result(shortname, resultset)}
     % endfor
     </tr> 
   % endfor
   </table>
+</%def>
+
+% if num_failures > 1:
+  <p><h2><font color="red">${num_failures} tests failed!</font></h2></p>
+% elif num_failures:
+  <p><h2><font color="red">${num_failures} test failed!</font></h2></p>
+% else:
+  <p><h2><font color="green">All tests passed!</font></h2></p>
+% endif
+
+% if cloud_to_prod:
+  % for prod_server in prod_servers:
+    <h2>Cloud to ${prod_server}</h2>
+    ${display_cloud_to_prod_result(prod_server)}
+  % endfor
 % endif
 
 % if http2_interop:
@@ -108,7 +116,9 @@
     <th>${server_lang}</th>
   % endfor
   % if cloud_to_prod:
-    <th>prod</th>
+    % for prod_server in prod_servers:
+      <th>${prod_server}</th>
+    % endfor
   % endif
   </tr>
   % for test_case in http2_cases:
@@ -122,8 +132,10 @@
       ${fill_one_http2_test_result(shortname, resultset)}
     % endfor
     % if cloud_to_prod:
-      <% shortname = 'cloud_to_prod:http2:%s' % test_case %>
-      ${fill_one_http2_test_result(shortname, resultset)}
+      % for prod_server in prod_servers:
+        <% shortname = 'cloud_to_prod:%s:http2:%s' % (prod_server, test_case) %>
+        ${fill_one_http2_test_result(shortname, resultset)}
+      % endfor
     % endif
     </tr>
   % endfor
diff --git a/tools/run_tests/package_targets.py b/tools/run_tests/package_targets.py
index 997bc57..4ca8279 100644
--- a/tools/run_tests/package_targets.py
+++ b/tools/run_tests/package_targets.py
@@ -68,11 +68,11 @@
   return jobspec
 
 
-class CSharpNugetTarget:
+class CSharpPackage:
   """Builds C# nuget packages."""
 
   def __init__(self):
-    self.name = 'csharp_nuget'
+    self.name = 'csharp_package'
     self.labels = ['package', 'csharp', 'windows']
 
   def pre_build_jobspecs(self):
@@ -87,11 +87,12 @@
   def __str__(self):
     return self.name
 
-class NodeNpmBinaryTarget:
-  """Builds Node NPM package and collects binaries"""
+
+class NodePackage:
+  """Builds Node NPM package and collects precompiled binaries"""
 
   def __init__(self):
-    self.name = 'node_npm_binary'
+    self.name = 'node_package'
     self.labels = ['package', 'node', 'linux']
 
   def pre_build_jobspecs(self):
@@ -103,6 +104,44 @@
         'tools/dockerfile/grpc_artifact_linux_x64',
         'tools/run_tests/build_package_node.sh')
 
+
+class RubyPackage:
+  """Collects ruby gems created in the artifact phase"""
+
+  def __init__(self):
+    self.name = 'ruby_package'
+    self.labels = ['package', 'ruby', 'linux']
+
+  def pre_build_jobspecs(self):
+    return []
+
+  def build_jobspec(self):
+    return create_docker_jobspec(
+        self.name,
+        'tools/dockerfile/grpc_artifact_linux_x64',
+        'tools/run_tests/build_package_ruby.sh')
+
+
+class PythonPackage:
+  """Collects python eggs and wheels created in the artifact phase"""
+
+  def __init__(self):
+    self.name = 'python_package'
+    self.labels = ['package', 'python', 'linux']
+
+  def pre_build_jobspecs(self):
+    return []
+
+  def build_jobspec(self):
+    return create_docker_jobspec(
+        self.name,
+        'tools/dockerfile/grpc_artifact_linux_x64',
+        'tools/run_tests/build_package_python.sh')
+
+
 def targets():
   """Gets list of supported targets"""
-  return [CSharpNugetTarget(), NodeNpmBinaryTarget()]
+  return [CSharpPackage(),
+          NodePackage(),
+          RubyPackage(),
+          PythonPackage()]
diff --git a/tools/run_tests/pre_build_csharp.sh b/tools/run_tests/pre_build_csharp.sh
index 4341c02..32466c2 100755
--- a/tools/run_tests/pre_build_csharp.sh
+++ b/tools/run_tests/pre_build_csharp.sh
@@ -39,8 +39,3 @@
 then
   nuget restore Grpc.sln
 fi
-
-if [ -n "$NUGET" ]
-then
-  $NUGET restore Grpc.sln
-fi
diff --git a/tools/run_tests/pre_build_node.sh b/tools/run_tests/pre_build_node.sh
index 28ce354..11f46d6 100755
--- a/tools/run_tests/pre_build_node.sh
+++ b/tools/run_tests/pre_build_node.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -29,8 +29,12 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+NODE_VERSION=$1
+source ~/.nvm/nvm.sh
 set -ex
 
+nvm use $NODE_VERSION
+
 export GRPC_CONFIG=${CONFIG:-opt}
 
 # Expire cache after 1 week
diff --git a/tools/run_tests/report_utils.py b/tools/run_tests/report_utils.py
index 35f2069..0032a98 100644
--- a/tools/run_tests/report_utils.py
+++ b/tools/run_tests/report_utils.py
@@ -1,4 +1,4 @@
-# Copyright 2015, Google Inc.
+# Copyright 2015-2016, Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -77,7 +77,7 @@
 
 def render_interop_html_report(
   client_langs, server_langs, test_cases, auth_test_cases, http2_cases, 
-  resultset, num_failures, cloud_to_prod, http2_interop):
+  resultset, num_failures, cloud_to_prod, prod_servers, http2_interop):
   """Generate HTML report for interop tests."""
   template_file = 'tools/run_tests/interop_html_report.template'
   try:
@@ -94,6 +94,7 @@
   sorted_http2_cases = sorted(http2_cases)
   sorted_client_langs = sorted(client_langs)
   sorted_server_langs = sorted(server_langs)
+  sorted_prod_servers = sorted(prod_servers)
 
   args = {'client_langs': sorted_client_langs, 
           'server_langs': sorted_server_langs,
@@ -103,6 +104,7 @@
           'resultset': resultset,
           'num_failures': num_failures,
           'cloud_to_prod': cloud_to_prod,
+          'prod_servers': sorted_prod_servers,
           'http2_interop': http2_interop}
 
   html_report_out_dir = 'reports' 
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index fbc3b3c..4a670e0 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -422,12 +422,13 @@
     time.sleep(2)
 
 
-def cloud_to_prod_jobspec(language, test_case, docker_image=None, auth=False):
+def cloud_to_prod_jobspec(language, test_case, server_host_name, 
+                          server_host_detail, docker_image=None, auth=False):
   """Creates jobspec for cloud-to-prod interop test"""
   container_name = None
   cmdargs = [
-      '--server_host_override=grpc-test.sandbox.googleapis.com',
-      '--server_host=grpc-test.sandbox.googleapis.com',
+      '--server_host=%s' % server_host_detail[0],
+      '--server_host_override=%s' % server_host_detail[1],
       '--server_port=443',
       '--use_tls=true',
       '--test_case=%s' % test_case]
@@ -440,7 +441,8 @@
   cwd = language.client_cwd
 
   if docker_image:
-    container_name = dockerjob.random_name('interop_client_%s' % language.safename)
+    container_name = dockerjob.random_name('interop_client_%s' % 
+                                           language.safename)
     cmdline = docker_run_cmdline(cmdline,
                                  image=docker_image,
                                  cwd=cwd,
@@ -455,7 +457,8 @@
           cmdline=cmdline,
           cwd=cwd,
           environ=environ,
-          shortname='%s:%s:%s' % (suite_name, language, test_case),
+          shortname='%s:%s:%s:%s' % (suite_name, server_host_name, language, 
+                                     test_case),
           timeout_seconds=90,
           flake_retries=5 if args.allow_flakes else 0,
           timeout_retries=2 if args.allow_flakes else 0,
@@ -491,7 +494,7 @@
           cwd=cwd,
           environ=environ,
           shortname='cloud_to_cloud:%s:%s_server:%s' % (language, server_name,
-                                                 test_case),
+                                                        test_case),
           timeout_seconds=90,
           flake_retries=5 if args.allow_flakes else 0,
           timeout_retries=2 if args.allow_flakes else 0,
@@ -572,6 +575,21 @@
     'percent': 1.0 * passed / (passed + failed)
   }
 
+# A dictionary of prod servers to test. 
+# Format: server_name: (server_host, server_host_override, errors_allowed)
+# TODO(adelez): implement logic for errors_allowed where if the indicated tests
+# fail, they don't impact the overall test result.
+prod_servers = {
+    'default': ('grpc-test.sandbox.googleapis.com', 
+                'grpc-test.sandbox.googleapis.com', False),
+    'gateway_v2': ('grpc-test2.sandbox.googleapis.com', 
+                   'grpc-test2.sandbox.googleapis.com', True),
+    'cloud_gateway': ('216.239.32.255', 'grpc-test.sandbox.googleapis.com', 
+                      False),
+    'cloud_gateway_v2': ('216.239.32.255', 'grpc-test2.sandbox.googleapis.com', 
+                         True)
+}
+
 argp = argparse.ArgumentParser(description='Run interop tests.')
 argp.add_argument('-l', '--language',
                   choices=['all'] + sorted(_LANGUAGES),
@@ -589,6 +607,12 @@
                   action='store_const',
                   const=True,
                   help='Run cloud_to_prod_auth tests.')
+argp.add_argument('--prod_servers',
+                  choices=prod_servers.keys(),
+                  default=['default'],
+                  nargs='+',
+                  help=('The servers to run cloud_to_prod and '
+                        'cloud_to_prod_auth tests against.'))
 argp.add_argument('-s', '--server',
                   choices=['all'] + sorted(_SERVERS),
                   action='append',
@@ -688,32 +712,37 @@
     server_jobs[lang] = job
     server_addresses[lang] = ('localhost', job.mapped_port(_DEFAULT_SERVER_PORT))
 
-
   jobs = []
   if args.cloud_to_prod:
-    for language in languages:
-      for test_case in _TEST_CASES:
-        if not test_case in language.unimplemented_test_cases():
-          if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION:
-            test_job = cloud_to_prod_jobspec(language, test_case,
-                                             docker_image=docker_images.get(str(language)))
-            jobs.append(test_job)
+    for server_host_name in args.prod_servers:
+      for language in languages:
+        for test_case in _TEST_CASES:
+          if not test_case in language.unimplemented_test_cases():
+            if not test_case in _SKIP_ADVANCED + _SKIP_COMPRESSION:
+              test_job = cloud_to_prod_jobspec(
+                  language, test_case, server_host_name, 
+                  prod_servers[server_host_name],
+                  docker_image=docker_images.get(str(language)))
+              jobs.append(test_job)
 
-    if args.http2_interop:
-      for test_case in _HTTP2_TEST_CASES:
-        test_job = cloud_to_prod_jobspec(http2Interop, test_case,
-                                         docker_image=docker_images.get(str(http2Interop)))
-        jobs.append(test_job)
-
+      if args.http2_interop:
+        for test_case in _HTTP2_TEST_CASES:
+          test_job = cloud_to_prod_jobspec(
+              http2Interop, test_case, server_host_name, 
+              prod_servers[server_host_name],
+              docker_image=docker_images.get(str(http2Interop)))
+          jobs.append(test_job)
 
   if args.cloud_to_prod_auth:
-    for language in languages:
-      for test_case in _AUTH_TEST_CASES:
-        if not test_case in language.unimplemented_test_cases():
-          test_job = cloud_to_prod_jobspec(language, test_case,
-                                           docker_image=docker_images.get(str(language)),
-                                           auth=True)
-          jobs.append(test_job)
+    for server_host_name in args.prod_servers:
+      for language in languages:
+        for test_case in _AUTH_TEST_CASES:
+          if not test_case in language.unimplemented_test_cases():
+            test_job = cloud_to_prod_jobspec(
+                language, test_case, server_host_name, 
+                prod_servers[server_host_name],
+                docker_image=docker_images.get(str(language)), auth=True)
+            jobs.append(test_job)
 
   for server in args.override_server:
     server_name = server[0]
@@ -773,7 +802,8 @@
   report_utils.render_interop_html_report(
       set([str(l) for l in languages]), servers, _TEST_CASES, _AUTH_TEST_CASES,
       _HTTP2_TEST_CASES, resultset, num_failures,
-      args.cloud_to_prod_auth or args.cloud_to_prod, args.http2_interop)
+      args.cloud_to_prod_auth or args.cloud_to_prod, args.prod_servers, 
+      args.http2_interop)
 
 finally:
   # Check if servers are still running.
diff --git a/tools/run_tests/run_node.sh b/tools/run_tests/run_node.sh
index f93c9c3..40f61d7 100755
--- a/tools/run_tests/run_node.sh
+++ b/tools/run_tests/run_node.sh
@@ -28,8 +28,12 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+NODE_VERSION=$1
+source ~/.nvm/nvm.sh
 set -ex
 
+nvm use $NODE_VERSION
+
 CONFIG=${CONFIG:-opt}
 
 # change to grpc repo root
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 9e7b97c..f405866 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -186,7 +186,7 @@
     return True
 
   def dockerfile_dir(self, config, arch):
-    return None
+    return 'tools/dockerfile/test/cxx_jessie_%s' % _docker_arch_suffix(arch)
 
   def __str__(self):
     return self.make_target
@@ -194,13 +194,17 @@
 
 class NodeLanguage(object):
 
+  def __init__(self):
+    self.node_version = '0.12'
+
   def test_specs(self, config, args):
-    return [config.job_spec(['tools/run_tests/run_node.sh'], None,
+    return [config.job_spec(['tools/run_tests/run_node.sh', self.node_version],
+                            None,
                             environ=_FORCE_ENVIRON_FOR_WRAPPERS)]
 
   def pre_build_steps(self):
     # Default to 1 week cache expiration
-    return [['tools/run_tests/pre_build_node.sh']]
+    return [['tools/run_tests/pre_build_node.sh', self.node_version]]
 
   def make_targets(self, test_regex):
     return []
@@ -209,7 +213,7 @@
     return []
 
   def build_steps(self):
-    return [['tools/run_tests/build_node.sh']]
+    return [['tools/run_tests/build_node.sh', self.node_version]]
 
   def post_tests_steps(self):
     return []
@@ -221,7 +225,7 @@
     return False
 
   def dockerfile_dir(self, config, arch):
-    return None
+    return 'tools/dockerfile/test/node_jessie_%s' % _docker_arch_suffix(arch)
 
   def __str__(self):
     return 'node'
@@ -255,7 +259,7 @@
     return False
 
   def dockerfile_dir(self, config, arch):
-    return None
+    return 'tools/dockerfile/test/php_jessie_%s' % _docker_arch_suffix(arch)
 
   def __str__(self):
     return 'php'
@@ -311,7 +315,7 @@
     return False
 
   def dockerfile_dir(self, config, arch):
-    return None
+    return 'tools/dockerfile/test/python_jessie_%s' % _docker_arch_suffix(arch)
 
   def __str__(self):
     return 'python'
@@ -345,7 +349,7 @@
     return False
 
   def dockerfile_dir(self, config, arch):
-    return None
+    return 'tools/dockerfile/test/ruby_jessie_%s' % _docker_arch_suffix(arch)
 
   def __str__(self):
     return 'ruby'
@@ -430,7 +434,7 @@
     return False
 
   def dockerfile_dir(self, config, arch):
-    return None
+    return 'tools/dockerfile/test/csharp_jessie_%s' % _docker_arch_suffix(arch)
 
   def __str__(self):
     return 'csharp'
@@ -502,7 +506,7 @@
     return False
 
   def dockerfile_dir(self, config, arch):
-    return 'tools/dockerfile/grpc_sanity'
+    return 'tools/dockerfile/test/sanity'
 
   def __str__(self):
     return 'sanity'
@@ -626,19 +630,24 @@
     sys.exit(1)
 
 
+def _docker_arch_suffix(arch):
+  """Returns suffix to dockerfile dir to use."""
+  if arch == 'default' or arch == 'x64':
+    return 'x64'
+  elif arch == 'x86':
+    return 'x86'
+  else:
+    print 'Architecture %s not supported with current settings.' % arch
+    sys.exit(1)
+
+
 def _get_dockerfile_dir(language, cfg, arch):
   """Returns dockerfile to use"""
   custom = language.dockerfile_dir(cfg, arch)
   if custom:
     return custom
   else:
-    if arch == 'default' or arch == 'x64':
-      return 'tools/dockerfile/grpc_tests_multilang_x64'
-    elif arch == 'x86':
-      return 'tools/dockerfile/grpc_tests_multilang_x86'
-    else:
-      print 'Architecture %s not supported with current settings.' % arch
-      sys.exit(1)
+    return 'tools/dockerfile/grpc_tests_multilang_%s' % _docker_arch_suffix(arch)
 
 def runs_per_test_type(arg_str):
     """Auxilary function to parse the "runs_per_test" flag.