Skip to content
Merged
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: 1 addition & 1 deletion docs/data-sources/pack.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ data "spectrocloud_pack" "cni" {
- `name` (String) The name of the pack to search for.
- `registry_uid` (String) The unique identifier (UID) of the registry where the pack is located. Specify `registry_uid` to search within a specific registry.
- `type` (String) The type of pack to search for. Supported values are `helm`, `manifest`, `container`, `operator-instance`.
- `version` (String) The version of the pack to search for.
- `version` (String) Specify the version of the pack to search for. If not set, the latest available version from the specified registry will be used.

### Read-Only

Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/spectrocloud/terraform-provider-spectrocloud
go 1.22.5

require (
github.com/Masterminds/semver/v3 v3.1.1
github.com/go-openapi/strfmt v0.23.0
github.com/google/go-cmp v0.6.0
github.com/gorilla/mux v1.8.0
Expand All @@ -12,7 +13,7 @@ require (
github.com/robfig/cron v1.2.0
github.com/spectrocloud/gomi v1.14.1-0.20240214074114-c19394812368
github.com/spectrocloud/hapi v1.14.1-0.20240214071352-81f589b1d86d
github.com/spectrocloud/palette-sdk-go v0.0.0-20241227233030-cd7c351b4722
github.com/spectrocloud/palette-sdk-go v0.0.0-20250129091228-61bad491e5e8
github.com/stretchr/testify v1.10.0
gotest.tools v2.2.0+incompatible
k8s.io/api v0.23.5
Expand All @@ -23,7 +24,6 @@ require (

require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.1.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.2 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
github.com/agext/levenshtein v1.2.2 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -601,8 +601,8 @@ github.com/spectrocloud/gomi v1.14.1-0.20240214074114-c19394812368 h1:eY0BOyEbGu
github.com/spectrocloud/gomi v1.14.1-0.20240214074114-c19394812368/go.mod h1:LlZ9We4kDaELYi7Is0SVmnySuDhwphJLS6ZT4wXxFIk=
github.com/spectrocloud/hapi v1.14.1-0.20240214071352-81f589b1d86d h1:OMRbHxMJ1a+G1BYzvUYuMM0wLkYJPdnEOFx16faQ/UY=
github.com/spectrocloud/hapi v1.14.1-0.20240214071352-81f589b1d86d/go.mod h1:MktpRPnSXDTHsQrFSD+daJFQ1zMLSR+1gWOL31jVvWE=
github.com/spectrocloud/palette-sdk-go v0.0.0-20241227233030-cd7c351b4722 h1:Z574padnTtuCGPZfxhtbRGl3CtsAF8Zx+rc5aCo30zU=
github.com/spectrocloud/palette-sdk-go v0.0.0-20241227233030-cd7c351b4722/go.mod h1:Zv1+/Imw/lIOPAa+q9TzdyKiXmIzfLSwVTj11WemIZc=
github.com/spectrocloud/palette-sdk-go v0.0.0-20250129091228-61bad491e5e8 h1:VjJvMdivBh0TLPKJhtbZa1OYcGmbvoVIAHNN8v1cnvc=
github.com/spectrocloud/palette-sdk-go v0.0.0-20250129091228-61bad491e5e8/go.mod h1:Zv1+/Imw/lIOPAa+q9TzdyKiXmIzfLSwVTj11WemIZc=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
Expand Down
69 changes: 64 additions & 5 deletions spectrocloud/data_source_pack.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ package spectrocloud
import (
"context"
"fmt"
"github.com/Masterminds/semver/v3"
"github.com/spectrocloud/gomi/pkg/ptr"
"github.com/spectrocloud/palette-sdk-go/api/models"
"github.com/spectrocloud/palette-sdk-go/client"
"sort"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
Expand Down Expand Up @@ -46,7 +51,7 @@ func dataSourcePack() *schema.Resource {
},
"version": {
Type: schema.TypeString,
Description: "The version of the pack to search for.",
Description: "Specify the version of the pack to search for. If not set, the latest available version from the specified registry will be used.",
Computed: true,
Optional: true,
},
Expand All @@ -73,6 +78,7 @@ func dataSourcePack() *schema.Resource {

func dataSourcePackRead(_ context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
c := getV1ClientWithResourceContext(m, "")
var packName = ""

// Warning or errors can be collected in a slice type
var diags diag.Diagnostics
Expand Down Expand Up @@ -115,17 +121,24 @@ func dataSourcePackRead(_ context.Context, d *schema.ResourceData, m interface{}
and first part would be any random name to make overall pack name unique and 2nd part is actual pack name.
Thus, splitting pack name with '--' to get the correct pack name to find pack uuid
*/

if strings.Contains(v.(string), "--") {
v = strings.Split(v.(string), "--")[1]
}
packName = v.(string)
filters = append(filters, fmt.Sprintf("spec.name=%s", v.(string)))
}
if v, ok := d.GetOk("version"); ok {
filters = append(filters, fmt.Sprintf("spec.version=%s", v.(string)))
}
if v, ok := d.GetOk("registry_uid"); ok {
registryUID = v.(string)
}
if v, ok := d.GetOk("version"); ok {
filters = append(filters, fmt.Sprintf("spec.version=%s", v.(string)))
} else {
latestVersion := setLatestPackVersionToFilters(packName, registryUID, c)
if latestVersion != "" {
filters = append(filters, fmt.Sprintf("spec.version=%s", latestVersion))
}
}
if v, ok := d.GetOk("cloud"); ok {
clouds := expandStringList(v.(*schema.Set).List())
if !stringContains(clouds, "all") {
Expand All @@ -140,7 +153,7 @@ func dataSourcePackRead(_ context.Context, d *schema.ResourceData, m interface{}
return diag.FromErr(err)
}

packName := "unknown"
packName = "unknown"
if v, ok := d.GetOk("name"); ok {
packName = v.(string)
}
Expand Down Expand Up @@ -196,3 +209,49 @@ func dataSourcePackRead(_ context.Context, d *schema.ResourceData, m interface{}

return diags
}

func setLatestPackVersionToFilters(packName string, registryUID string, c *client.V1Client) string {
var packLayers = []models.V1PackLayer{"addon", "csi", "cni", "os", "kernel"}
var packTypes = []models.V1PackType{"spectro", "helm", "manifest", "oci"}
var packAddOnTypes = []string{"load balancer", "ingress", "logging", "monitoring", "security", "authentication",
"servicemesh", "system app", "app services", "registry", "csi", "cni", "integration", ""}

newFilter := &models.V1PackFilterSpec{
Name: &models.V1FilterString{
Eq: ptr.StringPtr(packName),
},
Type: packTypes,
Layer: packLayers,
Environment: []string{"all"},
AddOnType: packAddOnTypes,
}
if registryUID != "" {
newFilter.RegistryUID = []string{registryUID}
}
var newSort []*models.V1PackSortSpec
latestVersion := ""
packsResults, _ := c.SearchPacks(newFilter, newSort)
if len(packsResults) == 1 {
latestVersion, _ = getLatestVersion(packsResults[0].Spec.Registries)
return latestVersion
}
return ""
}

// getLatestVersion returns the latest version from a list of version strings.
func getLatestVersion(versions []*models.V1RegistryPackMetadata) (string, error) {
if len(versions) == 0 {
return "", fmt.Errorf("no versions provided")
}
semverVersions := make([]*semver.Version, len(versions))
for i, v := range versions {
ver, err := semver.NewVersion(v.LatestVersion)
if err != nil {
return "", fmt.Errorf("invalid version %q: %w", v, err)
}
semverVersions[i] = ver
}
sort.Sort(semver.Collection(semverVersions))

return semverVersions[len(semverVersions)-1].String(), nil
}
59 changes: 59 additions & 0 deletions spectrocloud/data_source_pack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package spectrocloud
import (
"context"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/spectrocloud/palette-sdk-go/api/models"
"github.com/stretchr/testify/assert"
"testing"
)
Expand Down Expand Up @@ -48,3 +49,61 @@ func TestDataSourcePacksReadHelmMultiPacks(t *testing.T) {
assertFirstDiagMessage(t, diags, "Multiple packs returned")

}

func TestGetLatestVersion(t *testing.T) {
t.Run("valid versions", func(t *testing.T) {
versions := []*models.V1RegistryPackMetadata{
{LatestVersion: "v1.0.0"},
{LatestVersion: "v1.2.0"},
{LatestVersion: "v1.1.0"},
}
latest, err := getLatestVersion(versions)

assert.NoError(t, err, "Expected no error")
assert.Equal(t, "1.2.0", latest, "The latest version should be returned")
})

t.Run("empty versions list", func(t *testing.T) {
versions := []*models.V1RegistryPackMetadata{}
latest, err := getLatestVersion(versions)

assert.Error(t, err, "Expected an error for empty versions list")
assert.Equal(t, "", latest, "No version should be returned")
assert.Equal(t, "no versions provided", err.Error(), "Expected specific error message")
})

t.Run("invalid version string", func(t *testing.T) {
versions := []*models.V1RegistryPackMetadata{
{LatestVersion: "1.0.0"},
{LatestVersion: "invalid-version"},
{LatestVersion: "1.1.0"},
}
latest, err := getLatestVersion(versions)

assert.Error(t, err, "Expected an error for invalid version string")
assert.Equal(t, "", latest, "No version should be returned for invalid input")
assert.Contains(t, err.Error(), "invalid version", "Error message should indicate invalid version")
})

t.Run("single version", func(t *testing.T) {
versions := []*models.V1RegistryPackMetadata{
{LatestVersion: "2.0.0"},
}
latest, err := getLatestVersion(versions)

assert.NoError(t, err, "Expected no error")
assert.Equal(t, "2.0.0", latest, "The single version should be returned")
})

t.Run("pre-release versions", func(t *testing.T) {
versions := []*models.V1RegistryPackMetadata{
{LatestVersion: "1.0.0-alpha"},
{LatestVersion: "1.0.0-beta"},
{LatestVersion: "1.0.0"},
}
latest, err := getLatestVersion(versions)

assert.NoError(t, err, "Expected no error")
assert.Equal(t, "1.0.0", latest, "The stable version should be returned as the latest")
})
}