diff --git a/monitoring/README.md b/monitoring/README.md
index f4413145b0..228ddaae13 100644
--- a/monitoring/README.md
+++ b/monitoring/README.md
@@ -58,7 +58,7 @@ authentication:
1. Set `GOOGLE_APPLICATION_CREDENTIALS` environment variable pointing to that file.
-## Samples
+## Stackdriver Monitoring Samples
To run the Stackdriver Monitoring Samples:
@@ -80,17 +80,54 @@ To run the Stackdriver Monitoring Samples:
Available commands:
create-metric Creates a logging metric.
+ create-uptime-check Creates an uptime check.
delete-metric Deletes a logging metric.
+ delete-uptime-check Deletes an uptime check config.
get-descriptor Gets a logging descriptor.
help Displays help for a command
list Lists commands
list-descriptors Lists logging descriptors.
+ list-uptime-check-ips Lists Uptime Check IPs.
+ list-uptime-checks Lists Uptime Check Configs.
read-timeseries-align Aggregates metrics for each timeseries.
read-timeseries-fields Reads Timeseries fields.
read-timeseries-reduce Aggregates metrics across multiple timeseries.
read-timeseries-simple Reads a timeseries.
write-timeseries Writes a timeseries.
+## Stackdriver Monitoring Alert Samples
+
+To run the Stackdriver Monitoring Alert Samples:
+
+ $ php alerts.php
+
+ Stackdriver Monitoring Alerts
+
+ Usage:
+ command [options] [arguments]
+
+ Options:
+ -h, --help Display this help message
+ -q, --quiet Do not output any message
+ -V, --version Display this application version
+ --ansi Force ANSI output
+ --no-ansi Disable ANSI output
+ -n, --no-interaction Do not ask any interactive question
+ -v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
+
+ Available commands:
+ backup-policies Back up alert policies.
+ create-channel Create a notification channel.
+ create-policy Create an alert policy.
+ delete-channel Delete a notification channel.
+ enable-policies Enable or disable alert policies in a project.
+ help Displays help for a command
+ list Lists commands
+ list-channels List alert channels.
+ list-policies List alert policies.
+ replace-channels Replace alert channels.
+ restore-policies Restore alert policies from a backup.
+
## The client library
This sample uses the [Google Cloud Client Library for PHP][google-cloud-php].
diff --git a/monitoring/alerts.php b/monitoring/alerts.php
new file mode 100644
index 0000000000..6a3df76822
--- /dev/null
+++ b/monitoring/alerts.php
@@ -0,0 +1,129 @@
+add(new Command('backup-policies'))
+ ->setDefinition($inputDefinition)
+ ->setDescription('Back up alert policies.')
+ ->setCode(function ($input, $output) {
+ alert_backup_policies(
+ $input->getArgument('project_id')
+ );
+ });
+
+$application->add(new Command('create-channel'))
+ ->setDefinition($inputDefinition)
+ ->setDescription('Create a notification channel.')
+ ->setCode(function ($input, $output) {
+ alert_create_channel(
+ $input->getArgument('project_id')
+ );
+ });
+
+$application->add(new Command('create-policy'))
+ ->setDefinition($inputDefinition)
+ ->setDescription('Create an alert policy.')
+ ->setCode(function ($input, $output) {
+ alert_create_policy(
+ $input->getArgument('project_id')
+ );
+ });
+
+$application->add(new Command('delete-channel'))
+ ->setDefinition(clone $inputDefinition)
+ ->addArgument('channel_id', InputArgument::REQUIRED, 'The notification channel ID to delete')
+ ->setDescription('Delete a notification channel.')
+ ->setCode(function ($input, $output) {
+ alert_delete_channel(
+ $input->getArgument('project_id'),
+ $input->getArgument('channel_id')
+ );
+ });
+
+$application->add(new Command('enable-policies'))
+ ->setDefinition(clone $inputDefinition)
+ ->addArgument('enable', InputArgument::OPTIONAL, 'Enable or disable the polcies', true)
+ ->addArgument('filter', InputArgument::OPTIONAL, 'Only enable/disable alert policies that match a filter.')
+ ->setDescription('Enable or disable alert policies in a project.')
+ ->setCode(function ($input, $output) {
+ alert_enable_policies(
+ $input->getArgument('project_id'),
+ $input->getArgument('enable'),
+ $input->getArgument('filter')
+ );
+ });
+
+$application->add(new Command('restore-policies'))
+ ->setDefinition($inputDefinition)
+ ->setDescription('Restore alert policies from a backup.')
+ ->setCode(function ($input, $output) {
+ alert_restore_policies(
+ $input->getArgument('project_id')
+ );
+ });
+
+$application->add(new Command('list-policies'))
+ ->setDefinition($inputDefinition)
+ ->setDescription('List alert policies.')
+ ->setCode(function ($input, $output) {
+ alert_list_policies(
+ $input->getArgument('project_id')
+ );
+ });
+
+$application->add(new Command('list-channels'))
+ ->setDefinition($inputDefinition)
+ ->setDescription('List alert channels.')
+ ->setCode(function ($input, $output) {
+ alert_list_channels(
+ $input->getArgument('project_id')
+ );
+ });
+$application->add(new Command('replace-channels'))
+ ->setDefinition(clone $inputDefinition)
+ ->addArgument('policy_id', InputArgument::REQUIRED, 'The policy id')
+ ->addArgument('channel_id', InputArgument::REQUIRED | InputArgument::IS_ARRAY, 'list of channel ids')
+ ->setDescription('Replace alert channels.')
+ ->setCode(function ($input, $output) {
+ alert_replace_channels(
+ $input->getArgument('project_id'),
+ $input->getArgument('policy_id'),
+ (array) $input->getArgument('channel_id')
+ );
+ });
+
+// for testing
+if (getenv('PHPUNIT_TESTS') === '1') {
+ return $application;
+}
+
+$application->run();
diff --git a/monitoring/composer.json b/monitoring/composer.json
index 8602815e2b..8ac88aa1cd 100644
--- a/monitoring/composer.json
+++ b/monitoring/composer.json
@@ -1,10 +1,19 @@
{
"require": {
"symfony/console": "^3.3",
- "google/cloud-monitoring": "~0.11"
+ "google/cloud-monitoring": "^0.13.0"
},
"autoload": {
"files": [
+ "src/alert_backup_policies.php",
+ "src/alert_create_channel.php",
+ "src/alert_create_policy.php",
+ "src/alert_delete_channel.php",
+ "src/alert_enable_policies.php",
+ "src/alert_list_channels.php",
+ "src/alert_list_policies.php",
+ "src/alert_replace_channels.php",
+ "src/alert_restore_policies.php",
"src/create_metric.php",
"src/create_uptime_check.php",
"src/delete_metric.php",
diff --git a/monitoring/phpunit.xml.dist b/monitoring/phpunit.xml.dist
index 9d297ccb03..49e0779afd 100644
--- a/monitoring/phpunit.xml.dist
+++ b/monitoring/phpunit.xml.dist
@@ -22,7 +22,9 @@
+ alerts.php
quickstart.php
+ monitoring.php
diff --git a/monitoring/src/alert_backup_policies.php b/monitoring/src/alert_backup_policies.php
new file mode 100644
index 0000000000..1a8918e280
--- /dev/null
+++ b/monitoring/src/alert_backup_policies.php
@@ -0,0 +1,61 @@
+ $projectId,
+ ]);
+ $channelClient = new NotificationChannelServiceClient([
+ 'projectId' => $projectId,
+ ]);
+ $projectName = $alertClient->projectName($projectId);
+
+ $record = [
+ 'project_name' => $projectName,
+ 'policies' => [],
+ 'channels' => [],
+ ];
+ $policies = $alertClient->listAlertPolicies($projectName);
+ foreach ($policies->iterateAllElements() as $policy) {
+ $record['policies'][] = json_decode($policy->serializeToJsonString());
+ }
+ $channels = $channelClient->listNotificationChannels($projectName);
+ foreach ($channels->iterateAllElements() as $channel) {
+ $record['channels'][] = json_decode($channel->serializeToJsonString());
+ }
+ file_put_contents('backup.json', json_encode($record, JSON_PRETTY_PRINT));
+ print('Backed up alert policies and notification channels to backup.json.');
+}
+// [END monitoring_alert_backup_policies]
diff --git a/monitoring/src/alert_create_channel.php b/monitoring/src/alert_create_channel.php
new file mode 100644
index 0000000000..ecb0adc44c
--- /dev/null
+++ b/monitoring/src/alert_create_channel.php
@@ -0,0 +1,48 @@
+ $projectId,
+ ]);
+ $projectName = $channelClient->projectName($projectId);
+
+ $channel = new NotificationChannel();
+ $channel->setDisplayName('Test Notification Channel');
+ $channel->setType('email');
+ $channel->setLabels(['email_address' => 'fake@example.com']);
+
+ $channel = $channelClient->createNotificationChannel($projectName, $channel);
+ printf('Created notification channel %s' . PHP_EOL, $channel->getName());
+}
+# [END monitoring_alert_create_channel]
diff --git a/monitoring/src/alert_create_policy.php b/monitoring/src/alert_create_policy.php
new file mode 100644
index 0000000000..9f587b4fb7
--- /dev/null
+++ b/monitoring/src/alert_create_policy.php
@@ -0,0 +1,62 @@
+ $projectId,
+ ]);
+ $projectName = $alertClient->projectName($projectId);
+
+ $policy = new AlertPolicy();
+ $policy->setDisplayName('Test Alert Policy');
+ $policy->setCombiner(ConditionCombinerType::PBOR);
+ /** @see https://cloud.google.com/monitoring/api/resources for a list of resource.type */
+ /** @see https://cloud.google.com/monitoring/api/metrics_gcp for a list of metric.type */
+ $policy->setConditions([new Condition([
+ 'display_name' => 'condition-1',
+ 'condition_threshold' => new MetricThreshold([
+ 'filter' => 'resource.type = "gce_instance" AND metric.type = "compute.googleapis.com/instance/cpu/utilization"',
+ 'duration' => new Duration(['seconds' => '60']),
+ 'comparison' => ComparisonType::COMPARISON_LT,
+ ])
+ ])]);
+
+ $policy = $alertClient->createAlertPolicy($projectName, $policy);
+ printf('Created alert policy %s' . PHP_EOL, $policy->getName());
+}
+# [END monitoring_alert_create_policy]
diff --git a/monitoring/src/alert_delete_channel.php b/monitoring/src/alert_delete_channel.php
new file mode 100644
index 0000000000..8f5c76fc89
--- /dev/null
+++ b/monitoring/src/alert_delete_channel.php
@@ -0,0 +1,42 @@
+ $projectId,
+ ]);
+ $channelName = $channelClient->notificationChannelName($projectId, $channelId);
+
+ $channelClient->deleteNotificationChannel($channelName);
+ printf('Deleted notification channel %s' . PHP_EOL, $channelName);
+}
+# [END monitoring_alert_delete_channel]
diff --git a/monitoring/src/alert_enable_policies.php b/monitoring/src/alert_enable_policies.php
new file mode 100644
index 0000000000..e3fc61a59d
--- /dev/null
+++ b/monitoring/src/alert_enable_policies.php
@@ -0,0 +1,69 @@
+ $projectId,
+ ]);
+ $projectName = $alertClient->projectName($projectId);
+
+ $policies = $alertClient->listAlertPolicies($projectName, [
+ 'filter' => $filter
+ ]);
+ foreach ($policies->iterateAllElements() as $policy) {
+ $isEnabled = $policy->getEnabled()->getValue();
+ if ($enable == $isEnabled) {
+ printf('Policy %s is already %s' . PHP_EOL,
+ $policy->getName(),
+ $isEnabled ? 'enabled' : 'disabled'
+ );
+ } else {
+ $policy->getEnabled()->setValue((bool) $enable);
+ $mask = new FieldMask();
+ $mask->setPaths(['enabled']);
+ $alertClient->updateAlertPolicy($policy, [
+ 'updateMask' => $mask
+ ]);
+ printf('%s %s' . PHP_EOL,
+ $enable ? 'Enabled' : 'Disabled',
+ $policy->getName()
+ );
+ }
+ }
+}
+// [END monitoring_alert_enable_policies]
diff --git a/monitoring/src/alert_list_channels.php b/monitoring/src/alert_list_channels.php
new file mode 100644
index 0000000000..3f49451fe9
--- /dev/null
+++ b/monitoring/src/alert_list_channels.php
@@ -0,0 +1,45 @@
+ $projectId,
+ ]);
+
+ $channels = $channelClient->listNotificationChannels(
+ $channelClient->projectName($projectId)
+ );
+ foreach ($channels->iterateAllElements() as $channel) {
+ printf('Name: %s (%s)' . PHP_EOL, $channel->getDisplayName(), $channel->getName());
+ }
+}
+// [END monitoring_alert_list_channels]
diff --git a/monitoring/src/alert_list_policies.php b/monitoring/src/alert_list_policies.php
new file mode 100644
index 0000000000..a7e997de24
--- /dev/null
+++ b/monitoring/src/alert_list_policies.php
@@ -0,0 +1,51 @@
+ $projectId,
+ ]);
+
+ $policies = $alertClient->listAlertPolicies(
+ $alertClient->projectName($projectId)
+ );
+ foreach ($policies->iterateAllElements() as $policy) {
+ printf('Name: %s (%s)' . PHP_EOL, $policy->getDisplayName(), $policy->getName());
+ }
+}
+// [END monitoring_alert_list_policies]
diff --git a/monitoring/src/alert_replace_channels.php b/monitoring/src/alert_replace_channels.php
new file mode 100644
index 0000000000..76cbe4ee46
--- /dev/null
+++ b/monitoring/src/alert_replace_channels.php
@@ -0,0 +1,61 @@
+ $projectId,
+ ]);
+
+ $channelClient = new NotificationChannelServiceClient([
+ 'projectId' => $projectId,
+ ]);
+ $policy = new AlertPolicy();
+ $policy->setName($alertClient->alertPolicyName($projectId, $alertPolicyId));
+
+ $newChannels = [];
+ foreach ($channelIds as $channelId) {
+ $newChannels[] = $channelClient->notificationChannelName($projectId, $channelId);
+ }
+ $policy->setNotificationChannels($newChannels);
+ $mask = new FieldMask();
+ $mask->setPaths(['notification_channels']);
+ $updatedPolicy = $alertClient->updateAlertPolicy($policy, [
+ 'updateMask' => $mask,
+ ]);
+ printf('Updated %s' . PHP_EOL, $updatedPolicy->getName());
+}
+// [END monitoring_alert_replace_channels]
diff --git a/monitoring/src/alert_restore_policies.php b/monitoring/src/alert_restore_policies.php
new file mode 100644
index 0000000000..2722a6a791
--- /dev/null
+++ b/monitoring/src/alert_restore_policies.php
@@ -0,0 +1,151 @@
+ $projectId,
+ ]);
+
+ $channelClient = new NotificationChannelServiceClient([
+ 'projectId' => $projectId,
+ ]);
+
+ print('Loading alert policies and notification channels from backup.json.' . PHP_EOL);
+ $projectName = $alertClient->projectName($projectId);
+ $record = json_decode(file_get_contents('backup.json'), true);
+ $isSameProject = $projectName == $record['project_name'];
+
+ # Convert dicts to AlertPolicies.
+ $policies = [];
+ foreach ($record['policies'] as $policyArray) {
+ $policy = new AlertPolicy();
+ $policy->mergeFromJsonString(json_encode($policyArray));
+ $policies[] = $policy;
+ }
+
+ # Convert dicts to NotificationChannels
+ $channels = [];
+ foreach (array_filter($record['channels']) as $channelArray) {
+ $channel = new NotificationChannel();
+ $channel->mergeFromJsonString(json_encode($channelArray));
+ $channels[] = $channel;
+ }
+
+ # Restore the channels.
+ $channelNameMap = [];
+ foreach ($channels as $channel) {
+ $updated = false;
+ printf('Updating channel %s' . PHP_EOL, $channel->getDisplayName());
+
+ # This field is immutable and it is illegal to specify a
+ # non-default value (UNVERIFIED or VERIFIED) in the
+ # Create() or Update() operations.
+ $channel->setVerificationStatus(
+ VerificationStatus::VERIFICATION_STATUS_UNSPECIFIED
+ );
+
+ if ($isSameProject) {
+ try {
+ $channelClient->updateNotificationChannel($channel);
+ $updated = true;
+ } catch (ApiException $e) {
+ # The channel was deleted. Create it below.
+ if ($e->getStatus() !== 'NOT_FOUND') {
+ throw $e;
+ }
+ }
+ }
+
+ if (!$updated) {
+ # The channel no longer exists. Recreate it.
+ $oldName = $channel->getName();
+ $channel->setName('');
+ $newChannel = $channelClient->createNotificationChannel(
+ $projectName,
+ $channel
+ );
+ $channelNameMap[$oldName] = $newChannel->getName();
+ }
+ }
+
+ # Restore the alerts
+ foreach ($policies as $policy) {
+ printf('Updating policy %s' . PHP_EOL, $policy->getDisplayName());
+ # These two fields cannot be set directly, so clear them.
+ $policy->setCreationRecord(null);
+ $policy->setMutationRecord(null);
+
+ $notificationChannels = $policy->getNotificationChannels();
+
+ # Update old channel names with new channel names.
+ foreach ($notificationChannels as $i => $channel) {
+ if (isset($channelNameMap[$channel])) {
+ $notificationChannels[$i] = $channelNameMap[$channel];
+ }
+ }
+
+ $updated = false;
+ if ($isSameProject) {
+ try {
+ $alertClient->updateAlertPolicy($policy);
+ $updated = true;
+ } catch (ApiException $e) {
+ # The policy was deleted. Create it below.
+ if ($e->getStatus() !== 'NOT_FOUND') {
+ throw $e;
+ }
+ }
+ }
+
+ if (!$updated) {
+ # The policy no longer exists. Recreate it.
+ $oldName = $policy->getName();
+ $policy->setName('');
+ foreach ($policy->getConditions() as $condition) {
+ $condition->setName('');
+ }
+ $policy = $alertClient->createAlertPolicy($projectName, $policy);
+ }
+ printf('Updated %s' . PHP_EOL, $policy->getName());
+ }
+ print('Restored alert policies and notification channels from backup.json.');
+}
+# [END monitoring_alert_enable_channel]
+# [END monitoring_alert_restore_policies]
+# [END monitoring_alert_update_channel]
diff --git a/monitoring/test/alertsTest.php b/monitoring/test/alertsTest.php
new file mode 100644
index 0000000000..0456f722be
--- /dev/null
+++ b/monitoring/test/alertsTest.php
@@ -0,0 +1,194 @@
+runAlertCommand('create-policy');
+ $this->assertRegexp($regexp, $output);
+
+ // Save the policy ID for later
+ preg_match($regexp, $output, $matches);
+ self::$policyId = $matches[1];
+ }
+
+ public function testEnablePolicies()
+ {
+ $policyName = AlertPolicyServiceClient::alertPolicyName(self::$projectId, self::$policyId);
+ $output = $this->runAlertCommand('enable-policies', [
+ 'filter' => sprintf('name = "%s"', $policyName),
+ 'enable' => true,
+ ]);
+ $this->assertContains(
+ sprintf('Policy %s is already enabled', $policyName),
+ $output
+ );
+
+ $output = $this->runAlertCommand('enable-policies', [
+ 'filter' => sprintf('name = "%s"', $policyName),
+ 'enable' => false,
+ ]);
+
+ $this->assertContains(sprintf('Disabled %s', $policyName), $output);
+ }
+
+ /** @depends testCreatePolicy */
+ public function testCreateChannel()
+ {
+ $regexp = '/^Created notification channel projects\/[\w-]+\/notificationChannels\/(\d+)$/';
+ $output = $this->runAlertCommand('create-channel');
+ $this->assertRegexp($regexp, $output);
+
+ // Save the channel ID for later
+ preg_match($regexp, $output, $matches);
+ self::$channelId = $matches[1];
+ }
+
+ /** @depends testCreateChannel */
+ public function testReplaceChannel()
+ {
+ $alertClient = new AlertPolicyServiceClient();
+ $channelClient = new NotificationChannelServiceClient();
+ $policyName = $alertClient->alertPolicyName(self::$projectId, self::$policyId);
+
+ $regexp = '/^Created notification channel projects\/[\w-]+\/notificationChannels\/(\d+)$/';
+ $output = $this->runAlertCommand('create-channel');
+ $this->assertRegexp($regexp, $output);
+ preg_match($regexp, $output, $matches);
+ $channelId1 = $matches[1];
+
+ $output = $this->runAlertCommand('create-channel');
+ $this->assertRegexp($regexp, $output);
+ preg_match($regexp, $output, $matches);
+ $channelId2 = $matches[1];
+
+ $output = $this->runAlertCommand('replace-channels', [
+ 'policy_id' => self::$policyId,
+ 'channel_id' => [$channelId1, $channelId2]
+ ]);
+ $this->assertContains(sprintf('Updated %s', $policyName), $output);
+
+ // verify the new channels have been added to the policy
+ $policy = $alertClient->getAlertPolicy($policyName);
+ $channels = $policy->getNotificationChannels();
+ $this->assertEquals(2, count($channels));
+ $this->assertEquals(
+ $newChannelName1 = $channelClient->notificationChannelName(self::$projectId, $channelId1),
+ $channels[0]
+ );
+ $this->assertEquals(
+ $newChannelName2 = $channelClient->notificationChannelName(self::$projectId, $channelId2),
+ $channels[1]
+ );
+
+ $output = $this->runAlertCommand('replace-channels', [
+ 'policy_id' => self::$policyId,
+ 'channel_id' => self::$channelId,
+ ]);
+ $this->assertContains(sprintf('Updated %s', $policyName), $output);
+
+ // verify the new channel replaces the previous channels added to the policy
+ $policy = $alertClient->getAlertPolicy($policyName);
+ $channels = $policy->getNotificationChannels();
+ $this->assertEquals(1, count($channels));
+ $this->assertEquals(
+ $channelClient->notificationChannelName(self::$projectId, self::$channelId),
+ $channels[0]
+ );
+
+ // remove the old chnnels
+ $channelClient->deleteNotificationChannel($newChannelName1);
+ $channelClient->deleteNotificationChannel($newChannelName2);
+ }
+
+ /** @depends testCreatePolicy */
+ public function testListPolciies()
+ {
+ // backup
+ $output = $this->runAlertCommand('list-policies');
+ $this->assertContains(self::$policyId, $output);
+ }
+
+ /** @depends testCreateChannel */
+ public function testListChannels()
+ {
+ // backup
+ $output = $this->runAlertCommand('list-channels');
+ $this->assertContains(self::$channelId, $output);
+ }
+
+ /** @depends testCreateChannel */
+ public function testBackupAndRestore()
+ {
+ // backup
+ $output = $this->runAlertCommand('backup-policies');
+ $this->assertContains('Backed up alert policies', $output);
+
+ $backupJson = file_get_contents(__DIR__ . '/../backup.json');
+ $backup = json_decode($backupJson, true);
+ $this->assertArrayHasKey('policies', $backup);
+ $this->assertArrayHasKey('channels', $backup);
+ $this->assertGreaterThan(0, count($backup['policies']));
+ $this->assertGreaterThan(0, count($backup['channels']));
+ $this->assertContains(self::$policyId, $backupJson);
+ $this->assertContains(self::$channelId, $backupJson);
+
+ // restore
+ $output = $this->runAlertCommand('restore-policies');
+ $this->assertContains('Restored alert policies', $output);
+ }
+
+ /** @depends testCreatePolicy */
+ public function testDeleteChannel()
+ {
+ // delete the policy first (required in order to delete the channel)
+ $alertClient = new AlertPolicyServiceClient();
+ $alertClient->deleteAlertPolicy(
+ $alertClient->alertPolicyName(self::$projectId, self::$policyId)
+ );
+
+ $output = $this->runAlertCommand('delete-channel', [
+ 'channel_id' => self::$channelId,
+ ]);
+ $this->assertContains('Deleted notification channel', $output);
+ $this->assertContains(self::$channelId, $output);
+ }
+
+ public function runAlertCommand($command, $args = [])
+ {
+ return $this->runCommand($command, $args + [
+ 'project_id' => self::$projectId
+ ]);
+ }
+}