From dc6434af40a7ae88b35a7d693c6ff686a538203b Mon Sep 17 00:00:00 2001 From: Guilhem Lettron Date: Fri, 6 Sep 2024 15:35:32 +0200 Subject: [PATCH] feat(akamai): unzip user content --- docs/release-notes.md | 1 + internal/providers/akamai/akamai.go | 9 +++- internal/providers/util/unzip.go | 36 +++++++++++++++ internal/providers/util/unzip_test.go | 63 +++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 internal/providers/util/unzip.go create mode 100644 internal/providers/util/unzip_test.go diff --git a/docs/release-notes.md b/docs/release-notes.md index c734609fe..6fc298861 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -12,6 +12,7 @@ nav_order: 9 - Support partitioning disk with mounted partitions - Support Proxmox VE +- Support gzipped Akamai user_data ### Changes diff --git a/internal/providers/akamai/akamai.go b/internal/providers/akamai/akamai.go index 648be3bee..0cd3b63eb 100644 --- a/internal/providers/akamai/akamai.go +++ b/internal/providers/akamai/akamai.go @@ -91,7 +91,14 @@ func fetchConfig(f *resource.Fetcher) (types.Config, report.Report, error) { return types.Config{}, report.Report{}, fmt.Errorf("decode base64: %w", err) } - return util.ParseConfig(f.Logger, data[:n]) + // The Linode Metadata Service can compress userdata. + // We have to gunzip if needed. + unzipData, err := util.TryUnzip(data[:n]) + if err != nil { + return types.Config{}, report.Report{}, fmt.Errorf("unzip: %w", err) + } + + return util.ParseConfig(f.Logger, unzipData) } // defaultTokenTTL is the time-to-live (TTL; in seconds) for an authorization diff --git a/internal/providers/util/unzip.go b/internal/providers/util/unzip.go new file mode 100644 index 000000000..a8193a113 --- /dev/null +++ b/internal/providers/util/unzip.go @@ -0,0 +1,36 @@ +// Copyright 2024 CoreOS, Inc. +// +// 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. + +package util + +import ( + "bytes" + "compress/gzip" + "io" + "net/http" +) + +func TryUnzip(raw []byte) ([]byte, error) { + if http.DetectContentType(raw) != "application/x-gzip" { + return raw, nil + } + + reader, err := gzip.NewReader(bytes.NewReader(raw)) + if err != nil { + return nil, err + } + defer reader.Close() + + return io.ReadAll(reader) +} diff --git a/internal/providers/util/unzip_test.go b/internal/providers/util/unzip_test.go new file mode 100644 index 000000000..91b4a4e71 --- /dev/null +++ b/internal/providers/util/unzip_test.go @@ -0,0 +1,63 @@ +// Copyright 2024 CoreOS, Inc. +// +// 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. + +package util_test + +import ( + "reflect" + "testing" + + "github.com/coreos/ignition/v2/internal/providers/util" +) + +func TestTryUnzip(t *testing.T) { + type args struct { + raw []byte + } + tests := []struct { + name string + args args + want []byte + wantErr bool + }{ + { + name: "uncompressed", + args: args{ + raw: []byte("hello world"), + }, + want: []byte("hello world"), + wantErr: false, + }, + { + name: "compressed", + args: args{ + raw: []byte{0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xcb, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, 0x2f, 0xca, 0x49, 0x01, 0x00, 0x85, 0x11, 0x4a, 0x0d, 0x0b, 0x00, 0x00, 0x00}, + }, + want: []byte("hello world"), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := util.TryUnzip(tt.args.raw) + if (err != nil) != tt.wantErr { + t.Errorf("TryUnzip() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("TryUnzip() = %v, want %v", got, tt.want) + } + }) + } +}