google-cloud-env 1.6.0 → 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +39 -3
- data/README.md +15 -16
- data/lib/google/cloud/env/compute_metadata.rb +883 -0
- data/lib/google/cloud/env/compute_smbios.rb +138 -0
- data/lib/google/cloud/env/file_system.rb +125 -0
- data/lib/google/cloud/env/lazy_value.rb +1003 -0
- data/lib/google/cloud/env/variables.rb +76 -0
- data/lib/google/cloud/env/version.rb +5 -1
- data/lib/google/cloud/env.rb +197 -170
- metadata +15 -150
@@ -0,0 +1,138 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2023 Google LLC
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require "google/cloud/env/lazy_value"
|
18
|
+
|
19
|
+
module Google
|
20
|
+
module Cloud
|
21
|
+
class Env
|
22
|
+
##
|
23
|
+
# Access to the SMBIOS information needed to determine if this Ruby
|
24
|
+
# process is running on a Google compute platform.
|
25
|
+
#
|
26
|
+
# This information lives at a file system path on Linux, but in the
|
27
|
+
# Registry on Windows.
|
28
|
+
#
|
29
|
+
# You can provide an override to "mock out" the behavior of this object.
|
30
|
+
#
|
31
|
+
class ComputeSMBIOS
|
32
|
+
##
|
33
|
+
# Create an SMBIOS access object
|
34
|
+
#
|
35
|
+
def initialize
|
36
|
+
@product_name_cache = LazyValue.new { load_product_name }
|
37
|
+
@override_product_name = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# Read the product name. On a Google compute platform, this should
|
42
|
+
# include the word "Google".
|
43
|
+
#
|
44
|
+
# This method may read the file system (on Linux) or registry (on
|
45
|
+
# Windows) the first time it is called, but it will cache the result
|
46
|
+
# for subsequent calls.
|
47
|
+
#
|
48
|
+
# @return [String] Product name, or the empty string if not found.
|
49
|
+
#
|
50
|
+
def product_name
|
51
|
+
@override_product_name || @product_name_cache.get.first
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# The source of the product name data. Will be one of the following:
|
56
|
+
#
|
57
|
+
# * `:linux` - The data comes from the Linux SMBIOS under /sys
|
58
|
+
# * `:windows` - The data comes from the Windows Registry
|
59
|
+
# * `:error` - The data could not be obtained
|
60
|
+
# * `:override` - The data comes from an override
|
61
|
+
#
|
62
|
+
# This method may read the file system (on Linux) or registry (on
|
63
|
+
# Windows) the first time it is called, but it will cache the result
|
64
|
+
# for subsequent calls.
|
65
|
+
#
|
66
|
+
# @return [Symbol] The source
|
67
|
+
#
|
68
|
+
def product_name_source
|
69
|
+
@override_product_name ? :override : @product_name_cache.get.last
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Determine whether the SMBIOS state suggests that we are running on a
|
74
|
+
# Google compute platform.
|
75
|
+
#
|
76
|
+
# This method may read the file system (on Linux) or registry (on
|
77
|
+
# Windows) the first time it is called, but it will cache the result
|
78
|
+
# for subsequent calls.
|
79
|
+
#
|
80
|
+
# @return [true,false]
|
81
|
+
#
|
82
|
+
def google_compute?
|
83
|
+
product_name.include? "Google"
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# The current override value for the product name, either a string
|
88
|
+
# value, or nil to disable mocking.
|
89
|
+
#
|
90
|
+
# @return [nil,String]
|
91
|
+
#
|
92
|
+
attr_accessor :override_product_name
|
93
|
+
|
94
|
+
##
|
95
|
+
# Run the given block with the product name mock modified. This is
|
96
|
+
# generally used for debugging/testing/mocking.
|
97
|
+
#
|
98
|
+
# @param override_name [nil,String]
|
99
|
+
#
|
100
|
+
def with_override_product_name override_name
|
101
|
+
old_override = @override_product_name
|
102
|
+
begin
|
103
|
+
@override_product_name = override_name
|
104
|
+
yield
|
105
|
+
ensure
|
106
|
+
@override_product_name = old_override
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
# @private The Windows registry key path
|
113
|
+
WINDOWS_KEYPATH = "SYSTEM\\HardwareConfig\\Current"
|
114
|
+
# @private The Windows registry key name
|
115
|
+
WINDOWS_KEYNAME = "SystemProductName"
|
116
|
+
# @private The Linux file path
|
117
|
+
LINUX_FILEPATH = "/sys/class/dmi/id/product_name"
|
118
|
+
|
119
|
+
private_constant :WINDOWS_KEYPATH, :WINDOWS_KEYNAME, :LINUX_FILEPATH
|
120
|
+
|
121
|
+
def load_product_name
|
122
|
+
require "win32/registry"
|
123
|
+
Win32::Registry::HKEY_LOCAL_MACHINE.open WINDOWS_KEYPATH do |reg|
|
124
|
+
return [reg[WINDOWS_KEYNAME].to_s, :windows]
|
125
|
+
end
|
126
|
+
rescue LoadError
|
127
|
+
begin
|
128
|
+
File.open LINUX_FILEPATH do |file|
|
129
|
+
return [file.readline(chomp: true), :linux]
|
130
|
+
end
|
131
|
+
rescue IOError, SystemCallError
|
132
|
+
["", :error]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2023 Google LLC
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require "google/cloud/env/lazy_value"
|
18
|
+
|
19
|
+
module Google
|
20
|
+
module Cloud
|
21
|
+
class Env
|
22
|
+
##
|
23
|
+
# Access to file system contents.
|
24
|
+
#
|
25
|
+
# This is a simple class that reads the contents of objects in the file
|
26
|
+
# system, caching data so that subsequent accesses do not need to reread
|
27
|
+
# the file system.
|
28
|
+
#
|
29
|
+
# You can also "mock" the file system by providing a hash of overrides.
|
30
|
+
# If overrides are present, actual file system access is disabled; that
|
31
|
+
# is, overrides are "all or nothing".
|
32
|
+
#
|
33
|
+
# This class does not provide any controls for data size. If you read a
|
34
|
+
# large file, its contents will stay in memory for the lifetime of the
|
35
|
+
# Ruby process.
|
36
|
+
#
|
37
|
+
class FileSystem
|
38
|
+
##
|
39
|
+
# Create a file system access object with no overrides.
|
40
|
+
#
|
41
|
+
def initialize
|
42
|
+
@overrides = nil
|
43
|
+
@cache = LazyDict.new do |path, binary|
|
44
|
+
if binary
|
45
|
+
File.binread path
|
46
|
+
else
|
47
|
+
File.read path
|
48
|
+
end
|
49
|
+
rescue IOError, SystemCallError
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
# This mutex protects the overrides variable. Its setting (i.e.
|
53
|
+
# whether nil or an overrides hash) will not change within a
|
54
|
+
# synchronize block.
|
55
|
+
@mutex = Thread::Mutex.new
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Read the given file from the file system and return its contents.
|
60
|
+
#
|
61
|
+
# @param path [String] The path to the file.
|
62
|
+
# @param binary [boolean] Whether to read in binary mode. Defaults to
|
63
|
+
# false. This must be consistent across multiple requests for the
|
64
|
+
# same path; if it is not, an error will be raised.
|
65
|
+
# @return [String] if the file exists.
|
66
|
+
# @return [nil] if the file does not exist.
|
67
|
+
#
|
68
|
+
def read path, binary: false
|
69
|
+
result = false
|
70
|
+
@mutex.synchronize do
|
71
|
+
result = @overrides[path] if @overrides
|
72
|
+
end
|
73
|
+
result = @cache.get(path, binary) if result == false
|
74
|
+
if result && binary != (result.encoding == Encoding::ASCII_8BIT)
|
75
|
+
raise IOError, "binary encoding flag mismatch"
|
76
|
+
end
|
77
|
+
result
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# The overrides hash, or nil if overrides are not present.
|
82
|
+
# The hash maps paths to contents of the file at that path.
|
83
|
+
#
|
84
|
+
# @return [Hash{String => String},nil]
|
85
|
+
#
|
86
|
+
attr_reader :overrides
|
87
|
+
|
88
|
+
##
|
89
|
+
# Set the overrides hash. You can either provide a hash of file paths
|
90
|
+
# to content, or nil to disable overrides. If overrides are present,
|
91
|
+
# actual filesystem access is disabled; overrides are "all or nothing".
|
92
|
+
#
|
93
|
+
# @param new_overrides [Hash{String => String},nil]
|
94
|
+
#
|
95
|
+
def overrides= new_overrides
|
96
|
+
@mutex.synchronize do
|
97
|
+
@overrides = new_overrides
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Run the given block with the overrides replaced with the given hash
|
103
|
+
# (or nil to disable overrides in the block). The original overrides
|
104
|
+
# setting is restored at the end of the block. This is used for
|
105
|
+
# debugging/testing/mocking.
|
106
|
+
#
|
107
|
+
# @param temp_overrides [nil,Hash{String => String}]
|
108
|
+
#
|
109
|
+
def with_overrides temp_overrides
|
110
|
+
old_overrides = @overrides
|
111
|
+
begin
|
112
|
+
@mutex.synchronize do
|
113
|
+
@overrides = temp_overrides
|
114
|
+
end
|
115
|
+
yield
|
116
|
+
ensure
|
117
|
+
@mutex.synchronize do
|
118
|
+
@overrides = old_overrides
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|