From ef6c70ad08cdc36c4590f5205ee15ddf4c0b428d Mon Sep 17 00:00:00 2001 From: Lee Jongwoo Date: Sat, 13 Jun 2026 21:43:26 +0900 Subject: [PATCH] fix(#79): propagate load ip data errors --- ip/aws/ip_data.go | 15 +++++---------- ip/aws/ip_data_test.go | 17 +++++++++++++++++ ip/aws/provider.go | 5 ++++- ip/azure/ip_data.go | 15 +++++---------- ip/azure/ip_data_test.go | 12 ++++++++++++ ip/azure/provider.go | 5 ++++- ip/cloudflare/ip_data.go | 32 ++++++++++++++++++-------------- ip/cloudflare/ip_data_test.go | 17 ++++++++++++++++- ip/cloudflare/provider.go | 5 ++++- ip/gcp/ip_data.go | 11 ++++------- ip/gcp/ip_data_test.go | 11 +++++++++++ ip/gcp/provider.go | 5 ++++- 12 files changed, 104 insertions(+), 46 deletions(-) create mode 100644 ip/aws/ip_data_test.go diff --git a/ip/aws/ip_data.go b/ip/aws/ip_data.go index bae5a1f..3fde903 100644 --- a/ip/aws/ip_data.go +++ b/ip/aws/ip_data.go @@ -5,7 +5,6 @@ import ( "cloudip/util" "errors" "fmt" - "log" "net/http" "os" "strings" @@ -128,29 +127,25 @@ func (ipDataManagerAws *IpDataManagerAws) EnsureDataFile() error { return nil } -func (ipDataManagerAws *IpDataManagerAws) LoadIpData() *IpRangeDataAws { +func (ipDataManagerAws *IpDataManagerAws) LoadIpData() (*IpRangeDataAws, error) { if !ipDataManagerAws.IpRange.IsEmpty() { - return &ipDataManagerAws.IpRange + return &ipDataManagerAws.IpRange, nil } awsIpRangeData := IpRangeDataAws{} ipDataFile, err := os.Open(ipDataManagerAws.DataFilePath) if err != nil { - err = util.ErrorWithInfo(err, "error opening data file") - util.PrintErrorTrace(err) - log.Fatal(err) + return nil, util.ErrorWithInfo(err, "error opening data file") } defer ipDataFile.Close() err = util.ReadJSON(ipDataFile, &awsIpRangeData) if err != nil { - err = util.ErrorWithInfo(err, "error reading data file") - util.PrintErrorTrace(err) - log.Fatal(err) + return nil, util.ErrorWithInfo(err, "error reading data file") } ipDataManagerAws.IpRange = awsIpRangeData - return &ipDataManagerAws.IpRange + return &ipDataManagerAws.IpRange, nil } var ipDataManagerAws = &IpDataManagerAws{ diff --git a/ip/aws/ip_data_test.go b/ip/aws/ip_data_test.go new file mode 100644 index 0000000..4c03761 --- /dev/null +++ b/ip/aws/ip_data_test.go @@ -0,0 +1,17 @@ +package aws + +import ( + "path/filepath" + "testing" +) + +func TestAWSLoadIpDataReturnsErrorForMissingFile(t *testing.T) { + dir := t.TempDir() + manager := &IpDataManagerAws{ + DataFilePath: filepath.Join(dir, "missing.json"), + } + + if _, err := manager.LoadIpData(); err == nil { + t.Fatal("LoadIpData() error = nil, want error") + } +} diff --git a/ip/aws/provider.go b/ip/aws/provider.go index 74e9f4a..7ca7e89 100644 --- a/ip/aws/provider.go +++ b/ip/aws/provider.go @@ -11,7 +11,10 @@ type AWSProvider struct { func NewAWSProvider() *AWSProvider { return &AWSProvider{ BaseProvider: provider.NewBaseProvider("AWS", ipDataManagerAws, func(bp *provider.BaseProvider) error { - awsIpRangeData := *ipDataManagerAws.LoadIpData() + awsIpRangeData, err := ipDataManagerAws.LoadIpData() + if err != nil { + return err + } for _, prefix := range awsIpRangeData.Prefixes { bp.AddIPv4Range(prefix.IpPrefix) diff --git a/ip/azure/ip_data.go b/ip/azure/ip_data.go index e86c3d2..2d94787 100644 --- a/ip/azure/ip_data.go +++ b/ip/azure/ip_data.go @@ -5,7 +5,6 @@ import ( "cloudip/util" "errors" "fmt" - "log" "os" "sync" "time" @@ -142,29 +141,25 @@ func (ipDataManagerAzure *IpDataManagerAzure) EnsureDataFile() error { return nil } -func (ipDataManagerAzure *IpDataManagerAzure) LoadIpData() *IpRangeDataAzure { +func (ipDataManagerAzure *IpDataManagerAzure) LoadIpData() (*IpRangeDataAzure, error) { if !ipDataManagerAzure.IpRange.IsEmpty() { - return &ipDataManagerAzure.IpRange + return &ipDataManagerAzure.IpRange, nil } azureIpRangeData := IpRangeDataAzure{} ipDataFile, err := os.Open(ipDataManagerAzure.DataFilePath) if err != nil { - err = util.ErrorWithInfo(err, "error loading data file") - util.PrintErrorTrace(err) - log.Fatal(err) + return nil, util.ErrorWithInfo(err, "error loading data file") } defer ipDataFile.Close() err = util.ReadJSON(ipDataFile, &azureIpRangeData) if err != nil { - err = util.ErrorWithInfo(err, "error reading data file") - util.PrintErrorTrace(err) - log.Fatal(err) + return nil, util.ErrorWithInfo(err, "error reading data file") } ipDataManagerAzure.IpRange = azureIpRangeData - return &ipDataManagerAzure.IpRange + return &ipDataManagerAzure.IpRange, nil } var ipDataManagerAzure = &IpDataManagerAzure{ diff --git a/ip/azure/ip_data_test.go b/ip/azure/ip_data_test.go index db0cbd5..b861504 100644 --- a/ip/azure/ip_data_test.go +++ b/ip/azure/ip_data_test.go @@ -1,6 +1,7 @@ package azure import ( + "path/filepath" "sync" "testing" "time" @@ -42,3 +43,14 @@ func TestAzureEnsureDataURIConcurrentAccess(t *testing.T) { } } } + +func TestAzureLoadIpDataReturnsErrorForMissingFile(t *testing.T) { + dir := t.TempDir() + manager := &IpDataManagerAzure{ + DataFilePath: filepath.Join(dir, "missing.json"), + } + + if _, err := manager.LoadIpData(); err == nil { + t.Fatal("LoadIpData() error = nil, want error") + } +} diff --git a/ip/azure/provider.go b/ip/azure/provider.go index a151292..4474553 100644 --- a/ip/azure/provider.go +++ b/ip/azure/provider.go @@ -13,7 +13,10 @@ type AzureProvider struct { func NewAzureProvider() *AzureProvider { return &AzureProvider{ BaseProvider: provider.NewBaseProvider("Azure", ipDataManagerAzure, func(bp *provider.BaseProvider) error { - azureIpRangeData := *ipDataManagerAzure.LoadIpData() + azureIpRangeData, err := ipDataManagerAzure.LoadIpData() + if err != nil { + return err + } for _, dataObject := range azureIpRangeData.Values { for _, prefix := range dataObject.Properties.AddressPrefixes { diff --git a/ip/cloudflare/ip_data.go b/ip/cloudflare/ip_data.go index efd2638..19ac7a0 100644 --- a/ip/cloudflare/ip_data.go +++ b/ip/cloudflare/ip_data.go @@ -5,7 +5,6 @@ import ( "cloudip/util" "errors" "io" - "log" "os" "strings" ) @@ -125,34 +124,39 @@ func (m *IpDataManagerCloudflare) EnsureDataFile() error { return nil } -func (m *IpDataManagerCloudflare) LoadIpData() *IpRangeDataCloudflare { +func (m *IpDataManagerCloudflare) LoadIpData() (*IpRangeDataCloudflare, error) { if !m.IpRange.IsEmpty() { - return &m.IpRange + return &m.IpRange, nil + } + + v4CIDRs, err := readCIDRLines(m.DataFilePathV4) + if err != nil { + return nil, err + } + v6CIDRs, err := readCIDRLines(m.DataFilePathV6) + if err != nil { + return nil, err } data := IpRangeDataCloudflare{ - V4CIDRs: readCIDRLines(m.DataFilePathV4), - V6CIDRs: readCIDRLines(m.DataFilePathV6), + V4CIDRs: v4CIDRs, + V6CIDRs: v6CIDRs, } m.IpRange = data - return &m.IpRange + return &m.IpRange, nil } -func readCIDRLines(path string) []string { +func readCIDRLines(path string) ([]string, error) { file, err := os.Open(path) if err != nil { - err = util.ErrorWithInfo(err, "error opening data file") - util.PrintErrorTrace(err) - log.Fatal(err) + return nil, util.ErrorWithInfo(err, "error opening data file") } defer file.Close() content, err := io.ReadAll(file) if err != nil { - err = util.ErrorWithInfo(err, "error reading data file") - util.PrintErrorTrace(err) - log.Fatal(err) + return nil, util.ErrorWithInfo(err, "error reading data file") } lines := strings.Split(string(content), "\n") @@ -164,7 +168,7 @@ func readCIDRLines(path string) []string { } cidrs = append(cidrs, trimmed) } - return cidrs + return cidrs, nil } func writeCIDRLines(path string, cidrs []string) error { diff --git a/ip/cloudflare/ip_data_test.go b/ip/cloudflare/ip_data_test.go index 14becc7..e5c3a0c 100644 --- a/ip/cloudflare/ip_data_test.go +++ b/ip/cloudflare/ip_data_test.go @@ -71,7 +71,10 @@ func TestCloudflareDownloadDataWritesCIDRsAndSignature(t *testing.T) { t.Fatalf("metadata signature = %q, want %q", metadataManager.Metadata.Signature, "cf-etag") } - data := manager.LoadIpData() + data, err := manager.LoadIpData() + if err != nil { + t.Fatalf("LoadIpData() error = %v", err) + } if len(data.V4CIDRs) != 1 || data.V4CIDRs[0] != "173.245.48.0/20" { t.Fatalf("V4CIDRs = %#v, want Cloudflare IPv4 CIDR", data.V4CIDRs) } @@ -132,3 +135,15 @@ func TestCloudflareEnsureDataFileReusesFetchedDataForUpdate(t *testing.T) { t.Fatalf("metadata signature = %q, want %q", metadataManager.Metadata.Signature, "new-etag") } } + +func TestCloudflareLoadIpDataReturnsErrorForMissingFile(t *testing.T) { + dir := t.TempDir() + manager := &IpDataManagerCloudflare{ + DataFilePathV4: filepath.Join(dir, "missing-v4.txt"), + DataFilePathV6: filepath.Join(dir, "missing-v6.txt"), + } + + if _, err := manager.LoadIpData(); err == nil { + t.Fatal("LoadIpData() error = nil, want error") + } +} diff --git a/ip/cloudflare/provider.go b/ip/cloudflare/provider.go index 909a70d..a9ad8ed 100644 --- a/ip/cloudflare/provider.go +++ b/ip/cloudflare/provider.go @@ -11,7 +11,10 @@ type CloudflareProvider struct { func NewCloudflareProvider() *CloudflareProvider { return &CloudflareProvider{ BaseProvider: provider.NewBaseProvider("Cloudflare", ipDataManagerCloudflare, func(bp *provider.BaseProvider) error { - data := *ipDataManagerCloudflare.LoadIpData() + data, err := ipDataManagerCloudflare.LoadIpData() + if err != nil { + return err + } for _, cidr := range data.V4CIDRs { bp.AddIPv4Range(cidr) diff --git a/ip/gcp/ip_data.go b/ip/gcp/ip_data.go index 54d83b5..7cb0f37 100644 --- a/ip/gcp/ip_data.go +++ b/ip/gcp/ip_data.go @@ -5,7 +5,6 @@ import ( "cloudip/util" "errors" "fmt" - "log" "os" ) @@ -121,20 +120,18 @@ func (ipDataManagerGcp *IpDataManagerGcp) EnsureDataFile() error { return nil } -func (ipDataManagerGcp *IpDataManagerGcp) LoadIpData() *IpRangeDataGcp { +func (ipDataManagerGcp *IpDataManagerGcp) LoadIpData() (*IpRangeDataGcp, error) { if !ipDataManagerGcp.IpRange.IsEmpty() { - return &ipDataManagerGcp.IpRange + return &ipDataManagerGcp.IpRange, nil } gcpIpRangeData, err := ipDataManagerGcp.readDataFile() if err != nil { - util.PrintErrorTrace(util.ErrorWithInfo(err, "error opening data file")) - util.PrintErrorTrace(err) - log.Fatal(err) + return nil, err } ipDataManagerGcp.IpRange = *gcpIpRangeData - return &ipDataManagerGcp.IpRange + return &ipDataManagerGcp.IpRange, nil } func (ipDataManagerGcp *IpDataManagerGcp) readDataFile() (*IpRangeDataGcp, error) { diff --git a/ip/gcp/ip_data_test.go b/ip/gcp/ip_data_test.go index 63d93e3..c8c1369 100644 --- a/ip/gcp/ip_data_test.go +++ b/ip/gcp/ip_data_test.go @@ -55,3 +55,14 @@ func TestGCPEnsureDataFileReusesFetchedDataForUpdate(t *testing.T) { t.Fatalf("metadata signature = %q, want %q", metadataManager.Metadata.Signature, "new-sync-token") } } + +func TestGCPLoadIpDataReturnsErrorForMissingFile(t *testing.T) { + dir := t.TempDir() + manager := &IpDataManagerGcp{ + DataFilePath: filepath.Join(dir, "missing.json"), + } + + if _, err := manager.LoadIpData(); err == nil { + t.Fatal("LoadIpData() error = nil, want error") + } +} diff --git a/ip/gcp/provider.go b/ip/gcp/provider.go index 88699ee..edd8817 100644 --- a/ip/gcp/provider.go +++ b/ip/gcp/provider.go @@ -11,7 +11,10 @@ type GCPProvider struct { func NewGCPProvider() *GCPProvider { return &GCPProvider{ BaseProvider: provider.NewBaseProvider("GCP", ipDataManagerGcp, func(bp *provider.BaseProvider) error { - gcpIpRangeData := *ipDataManagerGcp.LoadIpData() + gcpIpRangeData, err := ipDataManagerGcp.LoadIpData() + if err != nil { + return err + } for _, prefix := range gcpIpRangeData.Prefixes { if prefix.Ipv4Prefix != "" {