diff --git a/storagecontrol/composer.json b/storagecontrol/composer.json index 76be4bb14..9514b416d 100644 --- a/storagecontrol/composer.json +++ b/storagecontrol/composer.json @@ -1,6 +1,6 @@ { "require": { - "google/cloud-storage-control": "^1.9" + "google/cloud-storage-control": "^1.12" }, "require-dev": { "google/cloud-storage": "^1.48.1" diff --git a/storagecontrol/src/create_rapid_cache.php b/storagecontrol/src/create_rapid_cache.php new file mode 100644 index 000000000..4e9b5993d --- /dev/null +++ b/storagecontrol/src/create_rapid_cache.php @@ -0,0 +1,86 @@ +bucketName('_', $bucketName); + + // The Rapid Cache ID must be the same as the zone. + $formattedName = $storageControlClient->rapidCacheName('_', $bucketName, $zone); + + // Rapid Cache Ultra requires a bucket with hierarchical namespace enabled. + $rapidCache = new RapidCache([ + 'name' => $formattedName, + 'zone' => $zone, + 'cache_type' => 'rapid-cache-ultra', + // Time to live (TTL) for cache entries: 86400 seconds (24 hours). + 'ttl' => new Duration(['seconds' => 86400]), + ]); + + $request = new CreateRapidCacheRequest([ + 'parent' => $formattedParent, + 'rapid_cache' => $rapidCache, + ]); + + // Creating a Rapid Cache is a long-running operation. This sample blocks + // until it completes. A totalPollTimeoutMillis of 0 waits with no time + // limit, instead of the client library default of 5 minutes. + $operation = $storageControlClient->createRapidCache($request); + $operation->pollUntilComplete(['totalPollTimeoutMillis' => 0]); + + if (!$operation->operationSucceeded()) { + printf('Error: %s' . PHP_EOL, $operation->getError()->getMessage()); + return; + } + + /** @var RapidCache $rapidCacheResult */ + $rapidCacheResult = $operation->getResult(); + printf('Created Rapid Cache: %s' . PHP_EOL, $rapidCacheResult->getName()); + printf('State: %s' . PHP_EOL, $rapidCacheResult->getState()); +} +# [END storage_control_create_rapid_cache] + +// The following 2 lines are only needed to run the samples +require_once __DIR__ . '/../../testing/sample_helpers.php'; +\Google\Cloud\Samples\execute_sample(__FILE__, __NAMESPACE__, $argv); diff --git a/storagecontrol/src/disable_rapid_cache.php b/storagecontrol/src/disable_rapid_cache.php new file mode 100644 index 000000000..3f46e6c99 --- /dev/null +++ b/storagecontrol/src/disable_rapid_cache.php @@ -0,0 +1,80 @@ +rapidCacheName('_', $bucketName, $rapidCacheId); + + $request = new DisableRapidCacheRequest([ + 'name' => $formattedName, + ]); + + // Disabling a Rapid Cache is a long-running operation. This sample waits + // for the long-running operation to complete. A totalPollTimeoutMillis of + // 0 waits with no time limit. + $operation = $storageControlClient->disableRapidCache($request); + $completed = $operation->pollUntilComplete([ + 'totalPollTimeoutMillis' => $timeoutMillis, + ]); + + if (!$completed) { + printf('Disable operation is still running: %s' . PHP_EOL, $operation->getName()); + return; + } + + if (!$operation->operationSucceeded()) { + printf('Error: %s' . PHP_EOL, $operation->getError()->getMessage()); + return; + } + + /** @var RapidCache $rapidCacheResult */ + $rapidCacheResult = $operation->getResult(); + printf('Disabled Rapid Cache: %s' . PHP_EOL, $rapidCacheResult->getName()); +} +# [END storage_control_disable_rapid_cache] + +// The following 2 lines are only needed to run the samples +require_once __DIR__ . '/../../testing/sample_helpers.php'; +\Google\Cloud\Samples\execute_sample(__FILE__, __NAMESPACE__, $argv); diff --git a/storagecontrol/src/get_rapid_cache.php b/storagecontrol/src/get_rapid_cache.php new file mode 100644 index 000000000..6960afab9 --- /dev/null +++ b/storagecontrol/src/get_rapid_cache.php @@ -0,0 +1,61 @@ +rapidCacheName('_', $bucketName, $rapidCacheId); + + $request = new GetRapidCacheRequest([ + 'name' => $formattedName, + ]); + + $response = $storageControlClient->getRapidCache($request); + + printf('Got Rapid Cache: %s' . PHP_EOL, $response->getName()); + printf('Zone: %s' . PHP_EOL, $response->getZone()); + printf('Cache type: %s' . PHP_EOL, $response->getCacheType()); + printf('State: %s' . PHP_EOL, $response->getState()); +} +# [END storage_control_get_rapid_cache] + +// The following 2 lines are only needed to run the samples +require_once __DIR__ . '/../../testing/sample_helpers.php'; +\Google\Cloud\Samples\execute_sample(__FILE__, __NAMESPACE__, $argv); diff --git a/storagecontrol/src/list_rapid_caches.php b/storagecontrol/src/list_rapid_caches.php new file mode 100644 index 000000000..e2bbe8f9a --- /dev/null +++ b/storagecontrol/src/list_rapid_caches.php @@ -0,0 +1,59 @@ +bucketName('_', $bucketName); + + $request = new ListRapidCachesRequest([ + 'parent' => $formattedName, + ]); + + $response = $storageControlClient->listRapidCaches($request); + + // The iterator handles pagination automatically. + foreach ($response as $rapidCache) { + printf('Rapid Cache name: %s' . PHP_EOL, $rapidCache->getName()); + } +} +# [END storage_control_list_rapid_caches] + +// The following 2 lines are only needed to run the samples +require_once __DIR__ . '/../../testing/sample_helpers.php'; +\Google\Cloud\Samples\execute_sample(__FILE__, __NAMESPACE__, $argv); diff --git a/storagecontrol/src/update_rapid_cache.php b/storagecontrol/src/update_rapid_cache.php new file mode 100644 index 000000000..6425505f9 --- /dev/null +++ b/storagecontrol/src/update_rapid_cache.php @@ -0,0 +1,87 @@ +rapidCacheName('_', $bucketName, $rapidCacheId); + + $rapidCache = new RapidCache([ + 'name' => $formattedName, + 'ttl' => new Duration(['seconds' => $ttlSeconds]), + ]); + + // Only the fields listed in the update mask are changed. + $updateMask = new FieldMask([ + 'paths' => ['ttl'], + ]); + + $request = new UpdateRapidCacheRequest([ + 'rapid_cache' => $rapidCache, + 'update_mask' => $updateMask, + ]); + + // Updating a Rapid Cache is a long-running operation. This sample blocks + // until it completes. A totalPollTimeoutMillis of 0 waits with no time + // limit, instead of the client library default of 5 minutes. + $operation = $storageControlClient->updateRapidCache($request); + $operation->pollUntilComplete(['totalPollTimeoutMillis' => 0]); + + if (!$operation->operationSucceeded()) { + printf('Error: %s' . PHP_EOL, $operation->getError()->getMessage()); + return; + } + + /** @var RapidCache $rapidCacheResult */ + $rapidCacheResult = $operation->getResult(); + printf('Updated Rapid Cache: %s' . PHP_EOL, $rapidCacheResult->getName()); + printf('TTL: %d seconds' . PHP_EOL, $rapidCacheResult->getTtl()->getSeconds()); +} +# [END storage_control_update_rapid_cache] + +// The following 2 lines are only needed to run the samples +require_once __DIR__ . '/../../testing/sample_helpers.php'; +\Google\Cloud\Samples\execute_sample(__FILE__, __NAMESPACE__, $argv); diff --git a/storagecontrol/test/rapidCacheTest.php b/storagecontrol/test/rapidCacheTest.php new file mode 100644 index 000000000..83dc1c26a --- /dev/null +++ b/storagecontrol/test/rapidCacheTest.php @@ -0,0 +1,175 @@ +createBucket( + sprintf('php-gcscontrol-rc-%s', $uniqueBucketId), + [ + 'location' => self::$location, + 'hierarchicalNamespace' => ['enabled' => true], + 'iamConfiguration' => ['uniformBucketLevelAccess' => ['enabled' => true]] + ] + ); + sleep(self::BUCKET_PROPAGATION_SECONDS); + } + + public static function tearDownAfterClass(): void + { + if (!self::$sourceBucket) { + return; + } + // Disable the Rapid Cache if the test did not, so that the bucket can + // be deleted once the cache has been removed. Errors are ignored. + if (self::$cacheName && !self::$cacheDisabled) { + try { + $storageControlClient = new StorageControlClient(); + $storageControlClient->disableRapidCache(new DisableRapidCacheRequest([ + 'name' => self::$cacheName, + ])); + } catch (\Exception $e) { + // Ignore errors: the cache may already be disabled. + } + } + // A bucket cannot be deleted until its disabled Rapid Cache has been + // fully removed, which can take more than two hours. Cleanup is + // best-effort: a short retry, after which the bucket is left behind + // for later cleanup. + for ($attempt = 1; $attempt <= self::DELETE_RETRY_ATTEMPTS; $attempt++) { + try { + self::$sourceBucket->delete(); + return; + } catch (ConflictException $e) { + if ($attempt < self::DELETE_RETRY_ATTEMPTS) { + sleep(self::DELETE_RETRY_INTERVAL_SECONDS); + } + } catch (\Exception $e) { + break; + } + } + fwrite(STDERR, sprintf( + 'Could not delete bucket %s: %s' . PHP_EOL, + self::$sourceBucket->name(), + isset($e) ? $e->getMessage() : 'unknown error' + )); + } + + public function testRapidCacheLifecycle() + { + $bucketName = self::$sourceBucket->name(); + // The Rapid Cache ID must be the same as the zone. + $cacheId = self::$zone; + $cacheName = StorageControlClient::rapidCacheName('_', $bucketName, $cacheId); + self::$cacheName = $cacheName; + + // Test create Rapid Cache + $output = $this->runFunctionSnippet('create_rapid_cache', [ + $bucketName, + self::$zone, + ]); + $this->assertStringContainsString(sprintf('Created Rapid Cache: %s', $cacheName), $output); + + // Test get Rapid Cache + $output = $this->runFunctionSnippet('get_rapid_cache', [ + $bucketName, + $cacheId, + ]); + $this->assertStringContainsString(sprintf('Got Rapid Cache: %s', $cacheName), $output); + $this->assertStringContainsString(sprintf('Zone: %s', self::$zone), $output); + $this->assertStringContainsString('Cache type: rapid-cache-ultra', $output); + $this->assertStringContainsString('State: running', $output); + + // Test list Rapid Caches + $output = $this->runFunctionSnippet('list_rapid_caches', [ + $bucketName, + ]); + $this->assertStringContainsString(sprintf('Rapid Cache name: %s', $cacheName), $output); + + // Test update Rapid Cache + $output = $this->runFunctionSnippet('update_rapid_cache', [ + $bucketName, + $cacheId, + 172800, + ]); + $this->assertStringContainsString(sprintf('Updated Rapid Cache: %s', $cacheName), $output); + $this->assertStringContainsString('TTL: 172800 seconds', $output); + + // Test disable Rapid Cache, with a bounded wait so that the test + // cannot hang on the long-running operation. + $output = $this->runFunctionSnippet('disable_rapid_cache', [ + $bucketName, + $cacheId, + self::DISABLE_TIMEOUT_MILLIS, + ]); + self::$cacheDisabled = true; + if (str_contains($output, 'Disable operation is still running')) { + // The operation did not finish in time; the cache state must + // already show "disabled". + $output = $this->runFunctionSnippet('get_rapid_cache', [ + $bucketName, + $cacheId, + ]); + $this->assertStringContainsString('State: disabled', $output); + } else { + $this->assertStringContainsString(sprintf('Disabled Rapid Cache: %s', $cacheName), $output); + } + } +}