diff --git a/src/Compute/Metadata.php b/src/Compute/Metadata.php new file mode 100644 index 000000000000..3351c4dfc1cf --- /dev/null +++ b/src/Compute/Metadata.php @@ -0,0 +1,114 @@ +getProjectId(); + * + * $val = $metadata->getProjectMetadata($key); + */ +class Metadata +{ + /** + * The metadata reader. + */ + private $reader; + + /** + * The project id. + */ + private $projectId; + + /** + * Whether or not running on GCE. + */ + private $onGCE; + + /** + * We use StreamReader for the default implementation for fetching the URL. + */ + public function __construct() + { + $this->reader = new StreamReader(); + } + + /** + * A method to replace the reader implementation. + */ + public function setReader($reader) + { + $this->reader = $reader; + } + + /** + * This method retrieves a single metadata value for a given path. + */ + public function get($path) + { + return $this->reader->read($path); + } + + /** + * This method detects the project id and returns it. + */ + public function getProjectId() + { + if (! isset($this->projectId)) { + $this->projectId = $this->reader->read('project/project-id'); + } + return $this->projectId; + } + + /** + * This method detects whether or not running on GCE. + */ + public function isRunningOnGCE() + { + if (! isset($this->onGCE)) { + $this->onGCE = $this->reader->onGCE(); + } + return $this->onGCE; + } + + /** + * This method fetches the project custom metadta and returns it. + */ + public function getProjectMetadata($key) + { + $path = 'project/attributes/'.$key; + return $this->get($path); + } + + /** + * This method fetches the instance custom metadta and returns it. + */ + public function getInstanceMetadata($key) + { + $path = 'instance/attributes/'.$key; + return $this->get($path); + } +} diff --git a/src/Compute/Metadata/Readers/StreamReader.php b/src/Compute/Metadata/Readers/StreamReader.php new file mode 100644 index 000000000000..8786c89ad3ae --- /dev/null +++ b/src/Compute/Metadata/Readers/StreamReader.php @@ -0,0 +1,85 @@ + array( + 'method' => 'GET', + 'header' => self::FLAVOR_HEADER, + ), + ); + $this->context = stream_context_create($options); + } + + /** + * A method to read the metadata value for a given path. + */ + public function read($path) + { + $url = self::BASE_URL.$path; + return file_get_contents($url, false, $this->context); + } + + /** + * A method to detect whether it's running on Compute Engine or not. + */ + public function onGCE() + { + // We use the hostname for failing faster on non-gce environment. + $url = 'http://'.self::HOST; + $result = @file_get_contents($url, false, $this->context); + if ($result != false + && array_key_exists('Metadata-Flavor', $http_response_header) + && $http_response_header['Metadata-Flavor'] == 'Google') { + return true; + } + return false; + } +} diff --git a/tests/ComputeMetadataTest.php b/tests/ComputeMetadataTest.php new file mode 100644 index 000000000000..f63cc086f352 --- /dev/null +++ b/tests/ComputeMetadataTest.php @@ -0,0 +1,86 @@ +metadata = new Metadata(); + $this->mock = $this->getMockBuilder( + '\Google\Cloud\Compute\Metadata\Readers\StreamReader') + ->setMethods(array('read', 'onGCE')) + ->getmock(); + $this->metadata->setReader($this->mock); + } + + public function testProjectMetadata() + { + $expected_path = 'project/attributes/mykey'; + $expected_val = 'myval'; + $this->mock->expects($this->once()) + ->method('read') + ->with($this->equalTo($expected_path)) + ->willReturn($expected_val); + $val = $this->metadata->getProjectMetadata('mykey'); + $this->assertEquals($expected_val, $val); + } + + public function testInstanceMetadata() + { + $expected_path = 'instance/attributes/mykey'; + $expected_val = 'myval'; + $this->mock->expects($this->once()) + ->method('read') + ->with($this->equalTo($expected_path)) + ->willReturn($expected_val); + $val = $this->metadata->getInstanceMetadata('mykey'); + $this->assertEquals($expected_val, $val); + } + + public function testGetProjectId() + { + $expected_path = 'project/project-id'; + $expected_val = 'my-project'; + $this->mock->expects($this->once()) + ->method('read') + ->with($this->equalTo($expected_path)) + ->willReturn($expected_val); + $project_id = $this->metadata->getProjectId(); + $this->assertEquals($expected_val, $project_id); + // Ensure this value is cached thus we `read` only once. + $this->metadata->getProjectId(); + } + + public function testIsRunningOnGCE() + { + $expected_val = true; + $this->mock->expects($this->once()) + ->method('onGCE') + ->willReturn($expected_val); + $onGCE = $this->metadata->isRunningOnGCE(); + $this->assertEquals($expected_val, $onGCE); + // Ensure this value is cached thus we call onGCE only once. + $this->metadata->isRunningOnGCE(); + } +}