google-cloud-env 1.6.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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