IMPALA-8065: Add OS distribution name in OSInfo

Before this change OsInfo::DebugString() would print two lines:
- OS version: the long name of the Linux kernel from /proc/version
- Clock: the type of clock used
After this change OsInfo::DebugString() will print three lines:
- OS distribution: the short name of the OS release.
  If Docker is being used this is the name of the Container OS.
- OS version: the long name of the Linux kernel from /proc/version.
  If Docker is being used this is the description of the Host Kernel.
- Clock: the type of clock used.

Tested locally, the displayed OS Info in Ubuntu16 dev box is:
OS distribution: Ubuntu 16.04.6 LTS
OS version: Linux version 4.15.0-65-generic (buildd@lcy01-amd64-017)
(gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.10))
Clock: clocksource: 'tsc', clockid_t: CLOCK_MONOTONIC

Also checked with diff OS in docker: centos, redhat, ubuntu, oracle,
debian to make sure /etc/os-release exists and PRETTY_NAME in that file.
Each OS picked one version to test.
Specially for centos6 and redhat6, which have redhat-release instead of
os-release, copied redhat-release into Ubuntu16 dev box and verified os
version in mini-cluster.

Added new backend test os-info-test.cc.

Change-Id: I848c9e53ee4e0bf8ae0874bb6da28e8efa7f7c8a
Reviewed-on: http://gerrit.cloudera.org:8080/14531
Reviewed-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com>
Tested-by: Impala Public Jenkins <impala-public-jenkins@cloudera.com>
diff --git a/be/src/util/CMakeLists.txt b/be/src/util/CMakeLists.txt
index e0bbda0..ef3fbb2 100644
--- a/be/src/util/CMakeLists.txt
+++ b/be/src/util/CMakeLists.txt
@@ -120,6 +120,7 @@
   metrics-test.cc
   min-max-filter-test.cc
   openssl-util-test.cc
+  os-info-test.cc
   os-util-test.cc
   parse-util-test.cc
   pretty-printer-test.cc
@@ -182,6 +183,7 @@
 ADD_UNIFIED_BE_LSAN_TEST(metrics-test "MetricsTest.*")
 ADD_UNIFIED_BE_LSAN_TEST(min-max-filter-test "MinMaxFilterTest.*")
 ADD_UNIFIED_BE_LSAN_TEST(openssl-util-test "OpenSSLUtilTest.*")
+ADD_UNIFIED_BE_LSAN_TEST(os-info-test "OsInfo.*")
 ADD_UNIFIED_BE_LSAN_TEST(os-util-test "OsUtil.*")
 ADD_UNIFIED_BE_LSAN_TEST(parse-util-test "ParseMemSpecs.*")
 ADD_UNIFIED_BE_LSAN_TEST(pretty-printer-test "PrettyPrinterTest.*")
diff --git a/be/src/util/os-info-test.cc b/be/src/util/os-info-test.cc
new file mode 100644
index 0000000..ebc5225
--- /dev/null
+++ b/be/src/util/os-info-test.cc
@@ -0,0 +1,28 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "os-info.h"
+#include "testutil/gtest-util.h"
+
+using namespace impala;
+
+// Test OsInfo can extract os_distribution and os_version correctly from local machine.
+TEST(OsInfo, GetOsVersion) {
+  OsInfo osinfo;
+  ASSERT_NE(osinfo.os_distribution(), "Unknown");
+  ASSERT_NE(osinfo.os_version(), "Unknown");
+}
diff --git a/be/src/util/os-info.cc b/be/src/util/os-info.cc
index cf76b72..0103e76 100644
--- a/be/src/util/os-info.cc
+++ b/be/src/util/os-info.cc
@@ -17,19 +17,26 @@
 
 #include "util/os-info.h"
 
-#include <iostream>
-#include <fstream>
-#include <sstream>
 #include <stdlib.h>
 #include <string.h>
+#include <fstream>
+#include <iostream>
+#include <sstream>
 
 #include <unistd.h>
+#include <boost/algorithm/string.hpp>
+#include <sys/stat.h>
 
 #include "common/names.h"
 
+using boost::algorithm::is_any_of;
+using boost::algorithm::split;
+using boost::algorithm::token_compress_on;
+
 namespace impala {
 
 bool OsInfo::initialized_ = false;
+string OsInfo::os_distribution_ = "Unknown";
 string OsInfo::os_version_ = "Unknown";
 clockid_t OsInfo::fast_clock_ = CLOCK_MONOTONIC;
 std::string OsInfo::clock_name_ =
@@ -46,10 +53,36 @@
 
 void OsInfo::Init() {
   DCHECK(!initialized_);
+  struct stat info;
+  // Read from /etc/os-release
+  if (stat("/etc/os-release", &info) == 0) {
+    ifstream os_distribution("/etc/os-release", ios::in);
+    string line;
+    while (os_distribution.good() && !os_distribution.eof()) {
+      getline(os_distribution, line);
+      vector<string> fields;
+      split(fields, line, is_any_of("="), token_compress_on);
+      if (fields[0].compare("PRETTY_NAME") == 0) {
+        os_distribution_ = fields[1].data();
+        // remove quotes around os distribution
+        os_distribution_.erase(
+            remove(os_distribution_.begin(), os_distribution_.end(), '\"'),
+            os_distribution_.end());
+        break;
+      }
+    }
+    if (os_distribution.is_open()) os_distribution.close();
+  } else if (stat("/etc/redhat-release", &info) == 0) {
+    // Only old distributions like centos 6, redhat 6
+    ifstream os_distribution("/etc/redhat-release", ios::in);
+    if (os_distribution.good()) getline(os_distribution, os_distribution_);
+    if (os_distribution.is_open()) os_distribution.close();
+  }
+
   // Read from /proc/version
-  ifstream version("/proc/version", ios::in);
-  if (version.good()) getline(version, os_version_);
-  if (version.is_open()) version.close();
+  ifstream os_version("/proc/version", ios::in);
+  if (os_version.good()) getline(os_version, os_version_);
+  if (os_version.is_open()) os_version.close();
 
   // Read the current clocksource to see if CLOCK_MONOTONIC is known to be fast. "tsc" is
   // fast, while "xen" is slow (40 times slower than "tsc" on EC2). If CLOCK_MONOTONIC is
@@ -76,9 +109,10 @@
 string OsInfo::DebugString() {
   DCHECK(initialized_);
   stringstream stream;
-  stream << "OS version: " << os_version_ << endl
+  stream << "OS distribution: " << os_distribution_ << endl
+         << "OS version: " << os_version_ << endl
          << "Clock: " << clock_name_ << endl;
   return stream.str();
 }
 
-}
+} // namespace impala
diff --git a/be/src/util/os-info.h b/be/src/util/os-info.h
index 295d0b2..6c9f404 100644
--- a/be/src/util/os-info.h
+++ b/be/src/util/os-info.h
@@ -32,6 +32,15 @@
   /// Initialize OsInfo.
   static void Init();
 
+  /// Simple name of the OS.
+  /// If Docker is used this is the name of Container OS.
+  static const std::string os_distribution() {
+    DCHECK(initialized_);
+    return os_distribution_;
+  }
+
+  /// The version of Linux kernel and the version of the compiler used to build it.
+  /// If Docker is used this is the host kernel.
   static const std::string os_version() {
     DCHECK(initialized_);
     return os_version_;
@@ -48,6 +57,7 @@
 
  private:
   static bool initialized_;
+  static std::string os_distribution_;
   static std::string os_version_;
   static clockid_t fast_clock_;
   static std::string clock_name_;