google-cloud-env 1.6.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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