root / test / py / ganeti.ssconf_unittest.py @ 560ef132
History | View | Annotate | Download (8.6 kB)
1 | 911dfc49 | Michael Hanselmann | #!/usr/bin/python
|
---|---|---|---|
2 | 911dfc49 | Michael Hanselmann | #
|
3 | 911dfc49 | Michael Hanselmann | |
4 | 911dfc49 | Michael Hanselmann | # Copyright (C) 2012 Google Inc.
|
5 | 911dfc49 | Michael Hanselmann | #
|
6 | 911dfc49 | Michael Hanselmann | # This program is free software; you can redistribute it and/or modify
|
7 | 911dfc49 | Michael Hanselmann | # it under the terms of the GNU General Public License as published by
|
8 | 911dfc49 | Michael Hanselmann | # the Free Software Foundation; either version 2 of the License, or
|
9 | 911dfc49 | Michael Hanselmann | # (at your option) any later version.
|
10 | 911dfc49 | Michael Hanselmann | #
|
11 | 911dfc49 | Michael Hanselmann | # This program is distributed in the hope that it will be useful, but
|
12 | 911dfc49 | Michael Hanselmann | # WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | 911dfc49 | Michael Hanselmann | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 | 911dfc49 | Michael Hanselmann | # General Public License for more details.
|
15 | 911dfc49 | Michael Hanselmann | #
|
16 | 911dfc49 | Michael Hanselmann | # You should have received a copy of the GNU General Public License
|
17 | 911dfc49 | Michael Hanselmann | # along with this program; if not, write to the Free Software
|
18 | 911dfc49 | Michael Hanselmann | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
19 | 911dfc49 | Michael Hanselmann | # 02110-1301, USA.
|
20 | 911dfc49 | Michael Hanselmann | |
21 | 911dfc49 | Michael Hanselmann | |
22 | 911dfc49 | Michael Hanselmann | """Script for testing ganeti.ssconf"""
|
23 | 911dfc49 | Michael Hanselmann | |
24 | 911dfc49 | Michael Hanselmann | import os |
25 | 911dfc49 | Michael Hanselmann | import unittest |
26 | 911dfc49 | Michael Hanselmann | import tempfile |
27 | 911dfc49 | Michael Hanselmann | import shutil |
28 | 911dfc49 | Michael Hanselmann | import errno |
29 | 911dfc49 | Michael Hanselmann | |
30 | 911dfc49 | Michael Hanselmann | from ganeti import utils |
31 | 911dfc49 | Michael Hanselmann | from ganeti import constants |
32 | 911dfc49 | Michael Hanselmann | from ganeti import errors |
33 | 911dfc49 | Michael Hanselmann | from ganeti import ssconf |
34 | 911dfc49 | Michael Hanselmann | |
35 | 911dfc49 | Michael Hanselmann | import testutils |
36 | def6577f | Helga Velroyen | import mock |
37 | 911dfc49 | Michael Hanselmann | |
38 | 911dfc49 | Michael Hanselmann | |
39 | 911dfc49 | Michael Hanselmann | class TestReadSsconfFile(unittest.TestCase): |
40 | 911dfc49 | Michael Hanselmann | def setUp(self): |
41 | 911dfc49 | Michael Hanselmann | self.tmpdir = tempfile.mkdtemp()
|
42 | 911dfc49 | Michael Hanselmann | |
43 | 911dfc49 | Michael Hanselmann | def tearDown(self): |
44 | 911dfc49 | Michael Hanselmann | shutil.rmtree(self.tmpdir)
|
45 | 911dfc49 | Michael Hanselmann | |
46 | 911dfc49 | Michael Hanselmann | def testReadDirectory(self): |
47 | 911dfc49 | Michael Hanselmann | self.assertRaises(EnvironmentError, ssconf.ReadSsconfFile, self.tmpdir) |
48 | 911dfc49 | Michael Hanselmann | |
49 | 911dfc49 | Michael Hanselmann | def testNonExistantFile(self): |
50 | 911dfc49 | Michael Hanselmann | testfile = utils.PathJoin(self.tmpdir, "does.not.exist") |
51 | 911dfc49 | Michael Hanselmann | |
52 | 911dfc49 | Michael Hanselmann | self.assertFalse(os.path.exists(testfile))
|
53 | 911dfc49 | Michael Hanselmann | |
54 | 911dfc49 | Michael Hanselmann | try:
|
55 | 911dfc49 | Michael Hanselmann | ssconf.ReadSsconfFile(testfile) |
56 | 911dfc49 | Michael Hanselmann | except EnvironmentError, err: |
57 | 911dfc49 | Michael Hanselmann | self.assertEqual(err.errno, errno.ENOENT)
|
58 | 911dfc49 | Michael Hanselmann | else:
|
59 | 911dfc49 | Michael Hanselmann | self.fail("Exception was not raised") |
60 | 911dfc49 | Michael Hanselmann | |
61 | 911dfc49 | Michael Hanselmann | def testEmptyFile(self): |
62 | 911dfc49 | Michael Hanselmann | testfile = utils.PathJoin(self.tmpdir, "empty") |
63 | 911dfc49 | Michael Hanselmann | |
64 | 911dfc49 | Michael Hanselmann | utils.WriteFile(testfile, data="")
|
65 | 911dfc49 | Michael Hanselmann | |
66 | 911dfc49 | Michael Hanselmann | self.assertEqual(ssconf.ReadSsconfFile(testfile), "") |
67 | 911dfc49 | Michael Hanselmann | |
68 | 911dfc49 | Michael Hanselmann | def testSingleLine(self): |
69 | 911dfc49 | Michael Hanselmann | testfile = utils.PathJoin(self.tmpdir, "data") |
70 | 911dfc49 | Michael Hanselmann | |
71 | 911dfc49 | Michael Hanselmann | for nl in range(0, 10): |
72 | 911dfc49 | Michael Hanselmann | utils.WriteFile(testfile, data="Hello World" + ("\n" * nl)) |
73 | 911dfc49 | Michael Hanselmann | |
74 | 911dfc49 | Michael Hanselmann | self.assertEqual(ssconf.ReadSsconfFile(testfile),
|
75 | 911dfc49 | Michael Hanselmann | "Hello World")
|
76 | 911dfc49 | Michael Hanselmann | |
77 | 911dfc49 | Michael Hanselmann | def testExactlyMaxSize(self): |
78 | 911dfc49 | Michael Hanselmann | testfile = utils.PathJoin(self.tmpdir, "data") |
79 | 911dfc49 | Michael Hanselmann | |
80 | 911dfc49 | Michael Hanselmann | data = "A" * ssconf._MAX_SIZE
|
81 | 911dfc49 | Michael Hanselmann | utils.WriteFile(testfile, data=data) |
82 | 911dfc49 | Michael Hanselmann | |
83 | 911dfc49 | Michael Hanselmann | self.assertEqual(os.path.getsize(testfile), ssconf._MAX_SIZE)
|
84 | 911dfc49 | Michael Hanselmann | |
85 | 911dfc49 | Michael Hanselmann | self.assertEqual(ssconf.ReadSsconfFile(testfile),
|
86 | 911dfc49 | Michael Hanselmann | data) |
87 | 911dfc49 | Michael Hanselmann | |
88 | 911dfc49 | Michael Hanselmann | def testLargeFile(self): |
89 | 911dfc49 | Michael Hanselmann | testfile = utils.PathJoin(self.tmpdir, "data") |
90 | 911dfc49 | Michael Hanselmann | |
91 | 911dfc49 | Michael Hanselmann | for size in [ssconf._MAX_SIZE + 1, ssconf._MAX_SIZE * 2]: |
92 | 911dfc49 | Michael Hanselmann | utils.WriteFile(testfile, data="A" * size)
|
93 | 911dfc49 | Michael Hanselmann | self.assertTrue(os.path.getsize(testfile) > ssconf._MAX_SIZE)
|
94 | 911dfc49 | Michael Hanselmann | self.assertRaises(RuntimeError, ssconf.ReadSsconfFile, testfile) |
95 | 911dfc49 | Michael Hanselmann | |
96 | 911dfc49 | Michael Hanselmann | |
97 | 911dfc49 | Michael Hanselmann | class TestSimpleStore(unittest.TestCase): |
98 | 911dfc49 | Michael Hanselmann | def setUp(self): |
99 | cc7f5bfc | Michael Hanselmann | self._tmpdir = tempfile.mkdtemp()
|
100 | cc7f5bfc | Michael Hanselmann | self.ssdir = utils.PathJoin(self._tmpdir, "files") |
101 | cc7f5bfc | Michael Hanselmann | lockfile = utils.PathJoin(self._tmpdir, "lock") |
102 | cc7f5bfc | Michael Hanselmann | |
103 | cc7f5bfc | Michael Hanselmann | os.mkdir(self.ssdir)
|
104 | cc7f5bfc | Michael Hanselmann | |
105 | cc7f5bfc | Michael Hanselmann | self.sstore = ssconf.SimpleStore(cfg_location=self.ssdir, |
106 | cc7f5bfc | Michael Hanselmann | _lockfile=lockfile) |
107 | 911dfc49 | Michael Hanselmann | |
108 | 911dfc49 | Michael Hanselmann | def tearDown(self): |
109 | cc7f5bfc | Michael Hanselmann | shutil.rmtree(self._tmpdir)
|
110 | cc7f5bfc | Michael Hanselmann | |
111 | cc7f5bfc | Michael Hanselmann | def _ReadSsFile(self, filename): |
112 | cc7f5bfc | Michael Hanselmann | return utils.ReadFile(utils.PathJoin(self.ssdir, "ssconf_%s" % filename)) |
113 | 911dfc49 | Michael Hanselmann | |
114 | 911dfc49 | Michael Hanselmann | def testInvalidKey(self): |
115 | 911dfc49 | Michael Hanselmann | self.assertRaises(errors.ProgrammerError, self.sstore.KeyToFilename, |
116 | 911dfc49 | Michael Hanselmann | "not a valid key")
|
117 | 911dfc49 | Michael Hanselmann | self.assertRaises(errors.ProgrammerError, self.sstore._ReadFile, |
118 | 911dfc49 | Michael Hanselmann | "not a valid key")
|
119 | 911dfc49 | Michael Hanselmann | |
120 | 911dfc49 | Michael Hanselmann | def testKeyToFilename(self): |
121 | 911dfc49 | Michael Hanselmann | for key in ssconf._VALID_KEYS: |
122 | 911dfc49 | Michael Hanselmann | result = self.sstore.KeyToFilename(key)
|
123 | cc7f5bfc | Michael Hanselmann | self.assertTrue(utils.IsBelowDir(self.ssdir, result)) |
124 | 911dfc49 | Michael Hanselmann | self.assertTrue(os.path.basename(result).startswith("ssconf_")) |
125 | 911dfc49 | Michael Hanselmann | |
126 | 911dfc49 | Michael Hanselmann | def testReadFileNonExistingFile(self): |
127 | 911dfc49 | Michael Hanselmann | filename = self.sstore.KeyToFilename(constants.SS_CLUSTER_NAME)
|
128 | 911dfc49 | Michael Hanselmann | |
129 | 911dfc49 | Michael Hanselmann | self.assertFalse(os.path.exists(filename))
|
130 | 911dfc49 | Michael Hanselmann | try:
|
131 | 911dfc49 | Michael Hanselmann | self.sstore._ReadFile(constants.SS_CLUSTER_NAME)
|
132 | 911dfc49 | Michael Hanselmann | except errors.ConfigurationError, err:
|
133 | 911dfc49 | Michael Hanselmann | self.assertTrue(str(err).startswith("Can't read ssconf file")) |
134 | 911dfc49 | Michael Hanselmann | else:
|
135 | 911dfc49 | Michael Hanselmann | self.fail("Exception was not raised") |
136 | 911dfc49 | Michael Hanselmann | |
137 | 911dfc49 | Michael Hanselmann | for default in ["", "Hello World", 0, 100]: |
138 | 911dfc49 | Michael Hanselmann | self.assertFalse(os.path.exists(filename))
|
139 | 911dfc49 | Michael Hanselmann | result = self.sstore._ReadFile(constants.SS_CLUSTER_NAME, default=default)
|
140 | 911dfc49 | Michael Hanselmann | self.assertEqual(result, default)
|
141 | 911dfc49 | Michael Hanselmann | |
142 | 911dfc49 | Michael Hanselmann | def testReadFile(self): |
143 | 911dfc49 | Michael Hanselmann | utils.WriteFile(self.sstore.KeyToFilename(constants.SS_CLUSTER_NAME),
|
144 | 911dfc49 | Michael Hanselmann | data="cluster.example.com")
|
145 | 911dfc49 | Michael Hanselmann | |
146 | 911dfc49 | Michael Hanselmann | self.assertEqual(self.sstore._ReadFile(constants.SS_CLUSTER_NAME), |
147 | 911dfc49 | Michael Hanselmann | "cluster.example.com")
|
148 | 911dfc49 | Michael Hanselmann | |
149 | 911dfc49 | Michael Hanselmann | self.assertEqual(self.sstore._ReadFile(constants.SS_CLUSTER_NAME, |
150 | 911dfc49 | Michael Hanselmann | default="something.example.com"),
|
151 | 911dfc49 | Michael Hanselmann | "cluster.example.com")
|
152 | 911dfc49 | Michael Hanselmann | |
153 | 9b4329e9 | Michael Hanselmann | def testReadAllNoFiles(self): |
154 | 9b4329e9 | Michael Hanselmann | self.assertEqual(self.sstore.ReadAll(), {}) |
155 | 9b4329e9 | Michael Hanselmann | |
156 | 9b4329e9 | Michael Hanselmann | def testReadAllSingleFile(self): |
157 | 9b4329e9 | Michael Hanselmann | utils.WriteFile(self.sstore.KeyToFilename(constants.SS_CLUSTER_NAME),
|
158 | 9b4329e9 | Michael Hanselmann | data="cluster.example.com")
|
159 | 9b4329e9 | Michael Hanselmann | self.assertEqual(self.sstore.ReadAll(), { |
160 | 9b4329e9 | Michael Hanselmann | constants.SS_CLUSTER_NAME: "cluster.example.com",
|
161 | 9b4329e9 | Michael Hanselmann | }) |
162 | 9b4329e9 | Michael Hanselmann | |
163 | cc7f5bfc | Michael Hanselmann | def testWriteFiles(self): |
164 | cc7f5bfc | Michael Hanselmann | values = { |
165 | cc7f5bfc | Michael Hanselmann | constants.SS_CLUSTER_NAME: "cluster.example.com",
|
166 | cc7f5bfc | Michael Hanselmann | constants.SS_CLUSTER_TAGS: "value\nwith\nnewlines\n",
|
167 | cc7f5bfc | Michael Hanselmann | constants.SS_INSTANCE_LIST: "",
|
168 | cc7f5bfc | Michael Hanselmann | } |
169 | cc7f5bfc | Michael Hanselmann | |
170 | cc7f5bfc | Michael Hanselmann | self.sstore.WriteFiles(values)
|
171 | cc7f5bfc | Michael Hanselmann | |
172 | cc7f5bfc | Michael Hanselmann | self.assertEqual(sorted(os.listdir(self.ssdir)), sorted([ |
173 | cc7f5bfc | Michael Hanselmann | "ssconf_cluster_name",
|
174 | cc7f5bfc | Michael Hanselmann | "ssconf_cluster_tags",
|
175 | cc7f5bfc | Michael Hanselmann | "ssconf_instance_list",
|
176 | cc7f5bfc | Michael Hanselmann | ])) |
177 | cc7f5bfc | Michael Hanselmann | |
178 | cc7f5bfc | Michael Hanselmann | self.assertEqual(self._ReadSsFile(constants.SS_CLUSTER_NAME), |
179 | cc7f5bfc | Michael Hanselmann | "cluster.example.com\n")
|
180 | cc7f5bfc | Michael Hanselmann | self.assertEqual(self._ReadSsFile(constants.SS_CLUSTER_TAGS), |
181 | cc7f5bfc | Michael Hanselmann | "value\nwith\nnewlines\n")
|
182 | cc7f5bfc | Michael Hanselmann | self.assertEqual(self._ReadSsFile(constants.SS_INSTANCE_LIST), "") |
183 | cc7f5bfc | Michael Hanselmann | |
184 | cc7f5bfc | Michael Hanselmann | def testWriteFilesUnknownKey(self): |
185 | cc7f5bfc | Michael Hanselmann | values = { |
186 | cc7f5bfc | Michael Hanselmann | "unknown key": "value", |
187 | cc7f5bfc | Michael Hanselmann | } |
188 | cc7f5bfc | Michael Hanselmann | |
189 | cc7f5bfc | Michael Hanselmann | self.assertRaises(errors.ProgrammerError, self.sstore.WriteFiles, |
190 | cc7f5bfc | Michael Hanselmann | values, dry_run=True)
|
191 | cc7f5bfc | Michael Hanselmann | |
192 | cc7f5bfc | Michael Hanselmann | self.assertEqual(os.listdir(self.ssdir), []) |
193 | cc7f5bfc | Michael Hanselmann | |
194 | cc7f5bfc | Michael Hanselmann | def testWriteFilesDryRun(self): |
195 | cc7f5bfc | Michael Hanselmann | values = { |
196 | cc7f5bfc | Michael Hanselmann | constants.SS_CLUSTER_NAME: "cluster.example.com",
|
197 | cc7f5bfc | Michael Hanselmann | } |
198 | cc7f5bfc | Michael Hanselmann | |
199 | cc7f5bfc | Michael Hanselmann | self.sstore.WriteFiles(values, dry_run=True) |
200 | cc7f5bfc | Michael Hanselmann | |
201 | cc7f5bfc | Michael Hanselmann | self.assertEqual(os.listdir(self.ssdir), []) |
202 | cc7f5bfc | Michael Hanselmann | |
203 | cc7f5bfc | Michael Hanselmann | def testWriteFilesNoValues(self): |
204 | cc7f5bfc | Michael Hanselmann | for dry_run in [False, True]: |
205 | cc7f5bfc | Michael Hanselmann | self.sstore.WriteFiles({}, dry_run=dry_run)
|
206 | cc7f5bfc | Michael Hanselmann | |
207 | cc7f5bfc | Michael Hanselmann | self.assertEqual(os.listdir(self.ssdir), []) |
208 | cc7f5bfc | Michael Hanselmann | |
209 | cc7f5bfc | Michael Hanselmann | def testWriteFilesTooLong(self): |
210 | cc7f5bfc | Michael Hanselmann | values = { |
211 | cc7f5bfc | Michael Hanselmann | constants.SS_INSTANCE_LIST: "A" * ssconf._MAX_SIZE,
|
212 | cc7f5bfc | Michael Hanselmann | } |
213 | cc7f5bfc | Michael Hanselmann | |
214 | cc7f5bfc | Michael Hanselmann | for dry_run in [False, True]: |
215 | cc7f5bfc | Michael Hanselmann | try:
|
216 | cc7f5bfc | Michael Hanselmann | self.sstore.WriteFiles(values, dry_run=dry_run)
|
217 | cc7f5bfc | Michael Hanselmann | except errors.ConfigurationError, err:
|
218 | cc7f5bfc | Michael Hanselmann | self.assertTrue(str(err).startswith("Value 'instance_list' has")) |
219 | cc7f5bfc | Michael Hanselmann | else:
|
220 | cc7f5bfc | Michael Hanselmann | self.fail("Exception was not raised") |
221 | cc7f5bfc | Michael Hanselmann | |
222 | cc7f5bfc | Michael Hanselmann | self.assertEqual(os.listdir(self.ssdir), []) |
223 | cc7f5bfc | Michael Hanselmann | |
224 | def6577f | Helga Velroyen | def testGetHvparamsForHypervisor(self): |
225 | def6577f | Helga Velroyen | hvparams = [("a", "A"), ("b", "B"), ("c", "C")] |
226 | def6577f | Helga Velroyen | ssconf_file_content = '\n'.join("%s=%s" % (key, value) for (key, value) |
227 | def6577f | Helga Velroyen | in hvparams)
|
228 | def6577f | Helga Velroyen | self.sstore._ReadFile = mock.Mock(return_value=ssconf_file_content)
|
229 | def6577f | Helga Velroyen | result = self.sstore.GetHvparamsForHypervisor("foo") |
230 | def6577f | Helga Velroyen | for (key, value) in hvparams: |
231 | def6577f | Helga Velroyen | self.assertTrue(key in result) |
232 | def6577f | Helga Velroyen | self.assertEqual(value, result[key])
|
233 | def6577f | Helga Velroyen | |
234 | 911dfc49 | Michael Hanselmann | |
235 | dffa96d6 | Michael Hanselmann | class TestVerifyClusterName(unittest.TestCase): |
236 | dffa96d6 | Michael Hanselmann | def setUp(self): |
237 | dffa96d6 | Michael Hanselmann | self.tmpdir = tempfile.mkdtemp()
|
238 | dffa96d6 | Michael Hanselmann | |
239 | dffa96d6 | Michael Hanselmann | def tearDown(self): |
240 | dffa96d6 | Michael Hanselmann | shutil.rmtree(self.tmpdir)
|
241 | dffa96d6 | Michael Hanselmann | |
242 | dffa96d6 | Michael Hanselmann | def testMissingFile(self): |
243 | dffa96d6 | Michael Hanselmann | tmploc = utils.PathJoin(self.tmpdir, "does-not-exist") |
244 | dffa96d6 | Michael Hanselmann | ssconf.VerifyClusterName(NotImplemented, _cfg_location=tmploc)
|
245 | dffa96d6 | Michael Hanselmann | |
246 | dffa96d6 | Michael Hanselmann | def testMatchingName(self): |
247 | dffa96d6 | Michael Hanselmann | tmpfile = utils.PathJoin(self.tmpdir, "ssconf_cluster_name") |
248 | dffa96d6 | Michael Hanselmann | |
249 | dffa96d6 | Michael Hanselmann | for content in ["cluster.example.com", "cluster.example.com\n\n"]: |
250 | dffa96d6 | Michael Hanselmann | utils.WriteFile(tmpfile, data=content) |
251 | dffa96d6 | Michael Hanselmann | ssconf.VerifyClusterName("cluster.example.com",
|
252 | dffa96d6 | Michael Hanselmann | _cfg_location=self.tmpdir)
|
253 | dffa96d6 | Michael Hanselmann | |
254 | dffa96d6 | Michael Hanselmann | def testNameMismatch(self): |
255 | dffa96d6 | Michael Hanselmann | tmpfile = utils.PathJoin(self.tmpdir, "ssconf_cluster_name") |
256 | dffa96d6 | Michael Hanselmann | |
257 | dffa96d6 | Michael Hanselmann | for content in ["something.example.com", "foobar\n\ncluster.example.com"]: |
258 | dffa96d6 | Michael Hanselmann | utils.WriteFile(tmpfile, data=content) |
259 | dffa96d6 | Michael Hanselmann | self.assertRaises(errors.GenericError, ssconf.VerifyClusterName,
|
260 | dffa96d6 | Michael Hanselmann | "cluster.example.com", _cfg_location=self.tmpdir) |
261 | dffa96d6 | Michael Hanselmann | |
262 | dffa96d6 | Michael Hanselmann | |
263 | 29a32ce5 | Michael Hanselmann | class TestVerifyKeys(unittest.TestCase): |
264 | 29a32ce5 | Michael Hanselmann | def testNoKeys(self): |
265 | 29a32ce5 | Michael Hanselmann | ssconf.VerifyKeys({}) |
266 | 29a32ce5 | Michael Hanselmann | |
267 | 29a32ce5 | Michael Hanselmann | def testValidKeys(self): |
268 | 29a32ce5 | Michael Hanselmann | ssconf.VerifyKeys(ssconf._VALID_KEYS) |
269 | 29a32ce5 | Michael Hanselmann | |
270 | 29a32ce5 | Michael Hanselmann | for key in ssconf._VALID_KEYS: |
271 | 29a32ce5 | Michael Hanselmann | ssconf.VerifyKeys([key]) |
272 | 29a32ce5 | Michael Hanselmann | |
273 | 29a32ce5 | Michael Hanselmann | def testInvalidKeys(self): |
274 | 29a32ce5 | Michael Hanselmann | for key in ["", ".", " ", "foo", "bar", "HelloWorld"]: |
275 | 29a32ce5 | Michael Hanselmann | self.assertRaises(errors.GenericError, ssconf.VerifyKeys, [key])
|
276 | 29a32ce5 | Michael Hanselmann | |
277 | 29a32ce5 | Michael Hanselmann | |
278 | 911dfc49 | Michael Hanselmann | if __name__ == "__main__": |
279 | 911dfc49 | Michael Hanselmann | testutils.GanetiTestProgram() |