From 23ce3e2616a09c396024a33ff9dd33aac8fad677 Mon Sep 17 00:00:00 2001
From: Jonatan Ivanov <jonatan.ivanov@gmail.com>
Date: Sat, 4 Dec 2021 17:21:10 -0800
Subject: [PATCH] Add OsInfoContributor

---
 .../InfoContributorAutoConfiguration.java     |  8 +++
 ...itional-spring-configuration-metadata.json |  6 +++
 ...InfoContributorAutoConfigurationTests.java | 12 +++++
 .../boot/actuate/info/OsInfoContributor.java  | 40 +++++++++++++++
 .../actuate/info/OsInfoContributorTests.java  | 42 +++++++++++++++
 .../src/docs/asciidoc/actuator/endpoints.adoc | 15 +++++-
 .../org/springframework/boot/info/OsInfo.java | 51 +++++++++++++++++++
 .../boot/info/OsInfoTests.java                | 38 ++++++++++++++
 8 files changed, 210 insertions(+), 2 deletions(-)
 create mode 100644 spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/OsInfoContributor.java
 create mode 100644 spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/OsInfoContributorTests.java
 create mode 100644 spring-boot-project/spring-boot/src/main/java/org/springframework/boot/info/OsInfo.java
 create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/info/OsInfoTests.java

diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/info/InfoContributorAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/info/InfoContributorAutoConfiguration.java
index c996e02cf5a1..a453e16b3b81 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/info/InfoContributorAutoConfiguration.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/info/InfoContributorAutoConfiguration.java
@@ -21,6 +21,7 @@
 import org.springframework.boot.actuate.info.GitInfoContributor;
 import org.springframework.boot.actuate.info.InfoContributor;
 import org.springframework.boot.actuate.info.JavaInfoContributor;
+import org.springframework.boot.actuate.info.OsInfoContributor;
 import org.springframework.boot.autoconfigure.AutoConfigureAfter;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -86,4 +87,11 @@ public JavaInfoContributor javaInfoContributor() {
 		return new JavaInfoContributor();
 	}
 
+	@Bean
+	@ConditionalOnEnabledInfoContributor(value = "os", fallback = InfoContributorFallback.DISABLE)
+	@Order(DEFAULT_ORDER)
+	public OsInfoContributor osInfoContributor() {
+		return new OsInfoContributor();
+	}
+
 }
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json
index 05e054d821a9..55a958d21fb6 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json
@@ -279,6 +279,12 @@
       "description": "Whether to enable Java info.",
       "defaultValue": false
     },
+    {
+      "name": "management.info.os.enabled",
+      "type": "java.lang.Boolean",
+      "description": "Whether to enable OS info.",
+      "defaultValue": false
+    },
     {
       "name": "management.metrics.binders.files.enabled",
       "type": "java.lang.Boolean",
diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/info/InfoContributorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/info/InfoContributorAutoConfigurationTests.java
index 3e62f7073426..88b7740db238 100644
--- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/info/InfoContributorAutoConfigurationTests.java
+++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/info/InfoContributorAutoConfigurationTests.java
@@ -27,10 +27,12 @@
 import org.springframework.boot.actuate.info.Info;
 import org.springframework.boot.actuate.info.InfoContributor;
 import org.springframework.boot.actuate.info.JavaInfoContributor;
+import org.springframework.boot.actuate.info.OsInfoContributor;
 import org.springframework.boot.autoconfigure.AutoConfigurations;
 import org.springframework.boot.info.BuildProperties;
 import org.springframework.boot.info.GitProperties;
 import org.springframework.boot.info.JavaInfo;
+import org.springframework.boot.info.OsInfo;
 import org.springframework.boot.test.context.runner.ApplicationContextRunner;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -151,6 +153,16 @@ void javaInfoContributor() {
 		});
 	}
 
+	@Test
+	void osInfoContributor() {
+		this.contextRunner.withPropertyValues("management.info.os.enabled=true").run((context) -> {
+			assertThat(context).hasSingleBean(OsInfoContributor.class);
+			Map<String, Object> content = invokeContributor(context.getBean(OsInfoContributor.class));
+			assertThat(content).containsKey("os");
+			assertThat(content.get("os")).isInstanceOf(OsInfo.class);
+		});
+	}
+
 	private Map<String, Object> invokeContributor(InfoContributor contributor) {
 		Info.Builder builder = new Info.Builder();
 		contributor.contribute(builder);
diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/OsInfoContributor.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/OsInfoContributor.java
new file mode 100644
index 000000000000..1014c0e781aa
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/info/OsInfoContributor.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012-2021 the original author or authors.
+ *
+ * Licensed 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
+ *
+ *      https://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.
+ */
+
+package org.springframework.boot.actuate.info;
+
+import org.springframework.boot.info.OsInfo;
+
+/**
+ * An {@link InfoContributor} that exposes {@link OsInfo}.
+ *
+ * @author Jonatan Ivanov
+ * @since 2.7.0
+ */
+public class OsInfoContributor implements InfoContributor {
+
+	private final OsInfo osInfo;
+
+	public OsInfoContributor() {
+		this.osInfo = new OsInfo();
+	}
+
+	@Override
+	public void contribute(Info.Builder builder) {
+		builder.withDetail("os", this.osInfo);
+	}
+
+}
diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/OsInfoContributorTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/OsInfoContributorTests.java
new file mode 100644
index 000000000000..25435c7032c3
--- /dev/null
+++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/info/OsInfoContributorTests.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2012-2021 the original author or authors.
+ *
+ * Licensed 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
+ *
+ *      https://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.
+ */
+
+package org.springframework.boot.actuate.info;
+
+import org.junit.jupiter.api.Test;
+
+import org.springframework.boot.info.JavaInfo;
+import org.springframework.boot.info.OsInfo;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link OsInfoContributor}
+ *
+ * @author Jonatan Ivanov
+ */
+public class OsInfoContributorTests {
+
+	@Test
+	void osInfoShouldBeAdded() {
+		OsInfoContributor osInfoContributor = new OsInfoContributor();
+		Info.Builder builder = new Info.Builder();
+		osInfoContributor.contribute(builder);
+		Info info = builder.build();
+		assertThat(info.getDetails().get("os")).isInstanceOf(OsInfo.class);
+	}
+
+}
diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/endpoints.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/endpoints.adoc
index bcb77b2bbd26..6e6545c6d609 100644
--- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/endpoints.adoc
+++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/actuator/endpoints.adoc
@@ -1169,13 +1169,18 @@ When appropriate, Spring auto-configures the following `InfoContributor` beans:
 | Exposes Java runtime information.
 | None.
 
+| `os`
+| {spring-boot-actuator-module-code}/info/OsInfoContributor.java[`OsInfoContributor`]
+| Exposes Operating System information.
+| None.
+
 |===
 
 Whether or not an individual contributor is enabled is controlled by its `management.info.<id>.enabled` property.
 Different contributors have different defaults for this property, depending on their prerequisites and the nature of the information that they expose.
 
-With no prerequisites to indicate that they should be enabled, the `env` and `java` contributors are disabled by default.
-You can enable them by setting the configprop:management.info.env.enabled[] or configprop:management.info.java.enabled[] properties to `true`.
+With no prerequisites to indicate that they should be enabled, the `env`, `java` and `os` contributors are disabled by default.
+You can enable them by setting the configprop:management.info.env.enabled[], configprop:management.info.java.enabled[] or configprop:management.info.os.enabled[] properties to `true`.
 
 The `build` and `git` info contributors are enabled by default.
 Each can be disabled by setting its `management.info.<id>.enabled` property to `false`.
@@ -1266,6 +1271,12 @@ The `info` endpoint publishes information about your Java runtime environment, s
 
 
 
+[[actuator.endpoints.info.os-information]]
+==== OS Information
+The `info` endpoint publishes information about your Operating System, see {spring-boot-module-api}/info/OsInfo.html[`OsInfo`] for more details.
+
+
+
 [[actuator.endpoints.info.writing-custom-info-contributors]]
 ==== Writing Custom InfoContributors
 To provide custom application information, you can register Spring beans that implement the {spring-boot-actuator-module-code}/info/InfoContributor.java[`InfoContributor`] interface.
diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/info/OsInfo.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/info/OsInfo.java
new file mode 100644
index 000000000000..409da21fdb60
--- /dev/null
+++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/info/OsInfo.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2012-2021 the original author or authors.
+ *
+ * Licensed 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
+ *
+ *      https://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.
+ */
+
+package org.springframework.boot.info;
+
+/**
+ * Information about the Operating System the application is running on.
+ *
+ * @author Jonatan Ivanov
+ * @since 2.7.0
+ */
+public class OsInfo {
+
+	private final String name;
+
+	private final String version;
+
+	private final String arch;
+
+	public OsInfo() {
+		this.name = System.getProperty("os.name");
+		this.version = System.getProperty("os.version");
+		this.arch = System.getProperty("os.arch");
+	}
+
+	public String getName() {
+		return this.name;
+	}
+
+	public String getVersion() {
+		return this.version;
+	}
+
+	public String getArch() {
+		return this.arch;
+	}
+
+}
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/info/OsInfoTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/info/OsInfoTests.java
new file mode 100644
index 000000000000..11e951b083b3
--- /dev/null
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/info/OsInfoTests.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012-2021 the original author or authors.
+ *
+ * Licensed 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
+ *
+ *      https://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.
+ */
+
+package org.springframework.boot.info;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link OsInfo}.
+ *
+ * @author Jonatan Ivanov
+ */
+public class OsInfoTests {
+
+	@Test
+	void osInfoIsAvailable() {
+		OsInfo osInfo = new OsInfo();
+		assertThat(osInfo.getName()).isEqualTo(System.getProperty("os.name"));
+		assertThat(osInfo.getVersion()).isEqualTo(System.getProperty("os.version"));
+		assertThat(osInfo.getArch()).isEqualTo(System.getProperty("os.arch"));
+	}
+
+}