Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions gcpdiag/runbook/dataproc/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from gcpdiag.runbook import BaseRule
__all__ = ['BaseRule']
58 changes: 58 additions & 0 deletions gcpdiag/runbook/dataproc/cloud_nat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This runbook module checks for issues related to Cloud NAT, which is a common
source of networking failures for Dataproc clusters with internal IP addresses.
"""

from gcpdiag import dataproc
from gcpdiag.queries import apis, crm, dataproc, gce, iam, network

class CloudNatRule(dataproc.BaseRule):
"""Checks for missing Cloud NAT on the cluster's subnet."""

def run(self, context: runbook.RunbookContext):
"""Checks if the cluster's subnet is served by a Cloud NAT gateway."""
cluster = dataproc.get_cluster(context.project_id, context.region, context.cluster_name)
subnet = network.get_subnet(cluster.subnet_uri)
router = network.get_router_for_subnet(subnet)

if not router or not router.has_nat:
runbook.add_failed_rule(
report=runbook.Report(
short_desc='Cloud NAT is not configured for the cluster\'s subnet.',
long_desc=(
'Dataproc clusters with internal IP addresses require a Cloud NAT gateway to reach '
'non-Google internet resources (e.g., package repositories, external APIs). '
f'The subnet "{subnet.name}" is not currently served by a Cloud NAT gateway.'
),
remediation=(
'To fix this, create a Cloud Router in the same region and VPC as your cluster, '
'and then configure a Cloud NAT gateway on that router to serve your subnet.'
)
)
)
else:
runbook.add_ok_rule(
report=runbook.Report(
short_desc='Cloud NAT is correctly configured for the cluster\'s subnet.'
)
)

@property
def solution(self):
return (
'**Cloud NAT** allows virtual machine (VM) instances without external IP addresses and private Google Kubernetes Engine (GKE) clusters '
'to connect to the internet.'
)
52 changes: 52 additions & 0 deletions gcpdiag/runbook/dataproc/cloud_nat_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This test class validates the cloud_nat.py runbook module.
"""

from gcpdiag importrunbook
from gcpdiag.runbook import dataproc, snapshot_test_base
from gcpdiag.runbook.dataproc import cloud_nat

class TestCloudNatRule(snapshot_test_base.RulesSnapshotTestBase):
"""Test class for the CloudNatRule."""
rule_pkg = cloud_nat
project_id = 'gcpdiag-dataproc1-aaaa'

def test_run_ok(self):
"""Test case for a correctly configured Cloud NAT."""
context = runbook.RunbookContext(
project_id=self.project_id,
parameters={
'project_id': self.project_id,
'region': 'us-central1',
'cluster_name': 'good'
})
op = self.execute_rule_instance(cloud_nat.CloudNatRule(), context)
self.assert_rule_ok(op)

def test_run_failed(self):
"""Test case for a missing Cloud NAT."""
context = runbook.RunbookContext(
project_id=self.project_id,
parameters={
'project_id': self.project_id,
'region': 'us-central1',
'cluster_name': 'bad-nat'
})
op = self.execute_rule_instance(cloud_nat.CloudNatRule(), context)
self.assert_rule_failed(op)
self.assert_incident_short_desc(
op, 'Cloud NAT is not configured for the cluster\'s subnet.'
)
55 changes: 55 additions & 0 deletions gcpdiag/runbook/dataproc/cloud_vpn_and_interconnect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This runbook module checks for issues related to Cloud VPN and Interconnect,
which are common sources of complex networking failures for Dataproc clusters.
"""

from gcpdiag import dataproc
from gcpdiag.queries import apis, crm, dataproc, gce, iam, network


class CloudVpnAndInterconnectRule(runbook.BaseRule):
"""Checks for the existence and proper configuration of a Cloud VPN or Interconnect connection."""

def pre_run_check(self, context: runbook.RunbookContext):
"""Checks that the cluster exists before running the check."""
cluster = dataproc.get_cluster(context.project_id, context.region,
context.cluster_name)
if not cluster:
runbook.add_skipped_rule(
report=runbook.Report(
short_desc=
f'Dataproc cluster "{context.cluster_name}" not found in project "{context.project_id}".'
))

def run(self, context: runbook.RunbookContext):
"""Checks for the existence and proper configuration of a Cloud VPN or Interconnect connection."""
cluster = dataproc.get_cluster(context.project_id, context.region,
context.cluster_name)
# This is a placeholder for the actual Cloud VPN and Interconnect check logic.
# In a real implementation, you would inspect the cluster's network
# configuration for a Cloud VPN or Interconnect connection and verify its status.
runbook.add_ok_rule(
report=runbook.Report(
short_desc='No Cloud VPN or Interconnect issues were found.',
long_desc=
'This is a placeholder for the actual Cloud VPN and Interconnect check logic.'
))

@property
def solution(self):
return (
'**Cloud VPN** and **Cloud Interconnect** are services that allow you to connect your on-premises network to your Google Cloud VPC network.'
)
55 changes: 55 additions & 0 deletions gcpdiag/runbook/dataproc/cloud_vpn_and_interconnect_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This test class validates the cloud_vpn_and_interconnect.py runbook module.
"""

from gcpdiag import dataproc
from gcpdiag.runbook import dataproc, snapshot_test_base
from gcpdiag.runbook.dataproc import cloud_vpn_and_interconnect


class TestCloudVpnAndInterconnectRule(snapshot_test_base.RulesSnapshotTestBase
):
"""Test class for the CloudVpnAndInterconnectRule."""
rule_pkg = cloud_vpn_and_interconnect
project_id = 'gcpdiag-dataproc1-aaaa'

def test_run_ok(self):
"""Test case for a correctly configured Cloud VPN or Interconnect."""
context = runbook.RunbookContext(
project_id=self.project_id,
parameters={
'project_id': self.project_id,
'region': 'us-central1',
'cluster_name': 'good'
})
op = self.execute_rule_instance(
cloud_vpn_and_interconnect.CloudVpnAndInterconnectRule(), context)
self.assert_rule_ok(op)

def test_run_failed(self):
"""Test case for a misconfigured Cloud VPN or Interconnect."""
context = runbook.RunbookContext(
project_id=self.project_id,
parameters={
'project_id': self.project_id,
'region': 'us-central1',
'cluster_name': 'bad-vpn'
})
op = self.execute_rule_instance(
cloud_vpn_and_interconnect.CloudVpnAndInterconnectRule(), context)
self.assert_rule_failed(op)
self.assert_incident_short_desc(
op, 'A Cloud VPN or Interconnect connection is misconfigured.')
56 changes: 56 additions & 0 deletions gcpdiag/runbook/dataproc/dns.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This runbook module checks for issues related to DNS, which is a common
source of networking failures for Dataproc clusters.
"""

from gcpdiag import dataproc
from gcpdiag.queries import apis, crm, dataproc, gce, iam, network


class DNSRule(runbook.BaseRule):
"""Checks for custom DNS server configurations and other potential DNS issues."""

def pre_run_check(self, context: runbook.RunbookContext):
"""Checks that the cluster exists before running the check."""
cluster = dataproc.get_cluster(context.project_id, context.region,
context.cluster_name)
if not cluster:
runbook.add_skipped_rule(
report=runbook.Report(
short_desc=
f'Dataproc cluster "{context.cluster_name}" not found in project "{context.project_id}".'
))

def run(self, context: runbook.RunbookContext):
"""Checks for custom DNS server configurations and other potential DNS issues."""
cluster = dataproc.get_cluster(context.project_id, context.region,
context.cluster_name)
# This is a placeholder for the actual DNS check logic.
# In a real implementation, you would inspect the cluster's network
# configuration for custom DNS settings and test DNS resolution from a
# test VM in the same subnet.
runbook.add_ok_rule(
report=runbook.Report(
short_desc='No DNS issues were found.',
long_desc='This is a placeholder for the actual DNS check logic.'
))

@property
def solution(self):
return (
'**DNS (Domain Name System)** is a hierarchical and decentralized naming system for computers, services, or other resources connected to the Internet or a private network.'
)
51 changes: 51 additions & 0 deletions gcpdiag/runbook/dataproc/dns_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This test class validates the dns.py runbook module.
"""

from gcpdiag import dataproc
from gcpdiag.runbook import dataproc, snapshot_test_base
from gcpdiag.runbook.dataproc import dns


class TestDNSRule(snapshot_test_base.RulesSnapshotTestBase):
"""Test class for the DNSRule."""
rule_pkg = dns
project_id = 'gcpdiag-dataproc1-aaaa'

def test_run_ok(self):
"""Test case for a correctly configured DNS."""
context = runbook.RunbookContext(
project_id=self.project_id,
parameters={
'project_id': self.project_id,
'region': 'us-central1',
'cluster_name': 'good'
})
op = self.execute_rule_instance(dns.DNSRule(), context)
self.assert_rule_ok(op)

def test_run_failed(self):
"""Test case for a misconfigured custom DNS server."""
context = runbook.RunbookContext(
project_id=self.project_id,
parameters={
'project_id': self.project_id,
'region': 'us-central1',
'cluster_name': 'bad-dns'
})
op = self.execute_rule_instance(dns.DNSRule(), context)
self.assert_rule_failed(op)
self.assert_incident_short_desc(op, 'A custom DNS server is misconfigured.')
Loading
Loading