Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Commitments support for Azure's reservations #302

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
b00b60e
types preparation
Apr 23, 2024
aec879f
more mapping impls for azure
Apr 24, 2024
4258d64
Merge branch 'max/PRICE-32/commitments' into max/PRICE-175/azure-comm…
Apr 24, 2024
9b2c734
Merge branch 'max/PRICE-32/commitments' into max/PRICE-175/azure-comm…
Apr 24, 2024
31bf423
working import + update
Apr 25, 2024
a8b97cd
fix getReservationResources
Apr 25, 2024
9f517f0
add term mapping to MapReservationImportToResource to mimic API's beh…
Apr 25, 2024
f55ce68
fix tests
Apr 25, 2024
a580d57
TestMapCommitmentToReservationResource
Apr 25, 2024
ad9e702
rename
Apr 25, 2024
5a61aab
mapping functions tests
Apr 25, 2024
4232527
working first step of acc test
Apr 25, 2024
a5de1a1
CheckDestroy
Apr 25, 2024
981e840
working state import step
Apr 25, 2024
fa0adda
working azure acceptance tests
Apr 25, 2024
4773767
get rid of the dummy test
Apr 25, 2024
3a44eee
add usage examples
Apr 25, 2024
c5fc0d3
fix populateCommitmentsResourceData
Apr 25, 2024
3f823cd
full acc tests
Apr 25, 2024
c8f40f6
get rid of productname from the matcher
Apr 25, 2024
015d6fe
flatten matcher
Apr 25, 2024
70a574d
regenerate docs
Apr 25, 2024
fd41e73
format tf
Apr 25, 2024
f8d18cd
Merge branch 'max/PRICE-32/commitments' into max/PRICE-175/azure-comm…
Apr 25, 2024
33ca452
regenerate docs
Apr 25, 2024
4faf74e
add descriptions
Apr 25, 2024
e6d78a6
Merge branch 'max/PRICE-32/commitments' into max/PRICE-175/azure-comm…
Apr 25, 2024
c440337
MapConfigsToCommitments impl
Apr 25, 2024
942e4cb
Merge branch 'max/PRICE-32/commitments' into max/PRICE-175/azure-comm…
Apr 25, 2024
878dbab
regenerate docs
Apr 25, 2024
1eec2f7
newline
Apr 25, 2024
401c5f5
return err from MapReservationImportToResource
Apr 26, 2024
ac4aafd
get rid of attr schema config
Apr 26, 2024
294d2f4
Merge branch 'max/PRICE-32/commitments' into max/PRICE-175/azure-comm…
Apr 26, 2024
bccc2a9
use common fields for cast ai commitment fields
Apr 30, 2024
d85e290
Merge branch 'max/PRICE-32/commitments' into max/PRICE-175/azure-comm…
May 7, 2024
3efa77b
flatten the structure, get rid of the separate commitments package
May 7, 2024
55b51b4
Merge branch 'max/PRICE-32/commitments' into max/PRICE-175/azure-comm…
May 7, 2024
7e2e210
regenerate sdk
May 7, 2024
a37ecd9
renames
May 7, 2024
1225d31
Merge branch 'max/PRICE-32/commitments' into max/PRICE-175/azure-comm…
May 7, 2024
dd0be15
renames
May 7, 2024
cfb8a08
dont export mapping functions
May 7, 2024
8f6b8f1
Merge branch 'max/PRICE-32/commitments' into max/PRICE-175/azure-comm…
May 7, 2024
2a7e811
dont export field names
May 7, 2024
13017ec
Merge branch 'max/PRICE-32/commitments' into max/PRICE-175/azure-comm…
May 7, 2024
ef84a23
Feature: Commitment assignments support (#304)
maxtwardowski May 7, 2024
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
65 changes: 30 additions & 35 deletions castai/reservations/fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,42 +22,37 @@ const (
FieldReservationExpirationDate = "expiration_date"
FieldReservationType = "type"
FieldReservationDeepLinkToReservation = "deep_link_to_reservation"
FieldReservationID = "reservation_id"
FieldReservationScopeResourceGroup = "scope_resource_group"
FieldReservationScopeSubscription = "scope_subscription"
FieldReservationScopeStatus = "scope_status"
FieldReservationScope = "scope"
FieldReservationTerm = "term"
FieldReservationStatus = "status"
)

var reservationResourceFields = []string{
FieldReservationName,
FieldReservationProvider,
FieldReservationRegion,
FieldReservationInstanceType,
FieldReservationPrice,
FieldReservationCount,
FieldReservationStartDate,
FieldReservationEndDate,
FieldReservationZoneId,
FieldReservationZoneName,
FieldReservationProductName,
FieldReservationQuantity,
FieldReservationPurchaseDate,
FieldReservationExpirationDate,
FieldReservationType,
FieldReservationDeepLinkToReservation,
}

var csvColumnAlias = map[string][]string{
FieldReservationName: {FieldReservationName},
FieldReservationProvider: {FieldReservationProvider},
FieldReservationRegion: {FieldReservationRegion},
FieldReservationInstanceType: {FieldReservationInstanceType, FieldReservationProductName},
FieldReservationPrice: {FieldReservationPrice},
FieldReservationCount: {FieldReservationCount, FieldReservationQuantity},
FieldReservationStartDate: {FieldReservationStartDate, FieldReservationPurchaseDate},
FieldReservationEndDate: {FieldReservationEndDate, FieldReservationExpirationDate},
FieldReservationZoneId: {FieldReservationZoneId},
FieldReservationZoneName: {FieldReservationZoneName},
FieldReservationProductName: {FieldReservationProductName},
FieldReservationQuantity: {FieldReservationQuantity},
FieldReservationPurchaseDate: {FieldReservationPurchaseDate},
FieldReservationExpirationDate: {FieldReservationExpirationDate},
FieldReservationType: {FieldReservationType},
FieldReservationDeepLinkToReservation: {FieldReservationDeepLinkToReservation},
FieldReservationName: {},
FieldReservationProvider: {},
FieldReservationRegion: {},
FieldReservationInstanceType: {FieldReservationProductName},
FieldReservationPrice: {},
FieldReservationCount: {FieldReservationQuantity},
FieldReservationStartDate: {FieldReservationPurchaseDate},
FieldReservationEndDate: {FieldReservationExpirationDate},
FieldReservationZoneId: {},
FieldReservationZoneName: {},
FieldReservationProductName: {},
FieldReservationQuantity: {},
FieldReservationPurchaseDate: {},
FieldReservationExpirationDate: {},
FieldReservationType: {},
FieldReservationDeepLinkToReservation: {},
FieldReservationID: {},
FieldReservationScopeResourceGroup: {},
FieldReservationScopeSubscription: {},
FieldReservationScopeStatus: {},
FieldReservationTerm: {},
FieldReservationStatus: {},
FieldReservationScope: {},
}
57 changes: 29 additions & 28 deletions castai/reservations/mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package reservations

import (
"fmt"
"github.com/castai/terraform-provider-castai/castai/sdk"
"github.com/samber/lo"
"strconv"
"strings"
"time"

"github.com/samber/lo"

"github.com/castai/terraform-provider-castai/castai/sdk"
)

type ReservationResource map[string]*string
Expand All @@ -21,7 +23,7 @@ func MapCsvRecordsToReservationResources(csvRecords [][]string) ([]*ReservationR
})

reservationRecords := csvRecords[1:]
fieldIndexes := mapReservationsHeaderToReservationFieldIndexes(normalizedCsvColumnNames)
fieldIndexes := MapReservationsHeaderToReservationFieldIndexes(normalizedCsvColumnNames)

reservations := make([]*ReservationResource, 0, len(reservationRecords))
for _, record := range reservationRecords {
Expand Down Expand Up @@ -88,12 +90,11 @@ func MapToReservationResourcesWithCommonFieldsOnly(reservationResources []*Reser
})
}

func mapReservationsHeaderToReservationFieldIndexes(columns []string) map[string]int {
indexes := make(map[string]int, len(reservationResourceFields))
for _, field := range reservationResourceFields {
func MapReservationsHeaderToReservationFieldIndexes(columns []string) map[string]int {
indexes := make(map[string]int, len(csvColumnAlias))
for field, aliases := range csvColumnAlias {
index := -1
aliases := csvColumnAlias[field]
for _, alias := range aliases {
for _, alias := range append([]string{field}, aliases...) {
_, fieldIdx, found := lo.FindIndexOf(columns, func(item string) bool {
return strings.ToLower(item) == alias
})
Expand All @@ -110,46 +111,46 @@ func mapReservationsHeaderToReservationFieldIndexes(columns []string) map[string
}

func mapRecordToReservationResource(fieldIndexes map[string]int, record []string) (*ReservationResource, error) {
provider, err := getRecordReservationProvider(fieldIndexes, record)
provider, err := GetRecordReservationProvider(fieldIndexes, record)
if err != nil {
return nil, err
}

return &ReservationResource{
FieldReservationName: getRecordFieldStringValue(FieldReservationName, fieldIndexes, record),
FieldReservationName: GetRecordFieldStringValue(FieldReservationName, fieldIndexes, record),
FieldReservationProvider: provider,
FieldReservationRegion: getRecordFieldStringValue(FieldReservationRegion, fieldIndexes, record),
FieldReservationInstanceType: getRecordFieldStringValue(FieldReservationInstanceType, fieldIndexes, record),
FieldReservationPrice: getRecordFieldStringValue(FieldReservationPrice, fieldIndexes, record),
FieldReservationCount: getRecordFieldStringValue(FieldReservationCount, fieldIndexes, record),
FieldReservationStartDate: getRecordFieldStringValue(FieldReservationStartDate, fieldIndexes, record),
FieldReservationEndDate: getRecordFieldStringValue(FieldReservationEndDate, fieldIndexes, record),
FieldReservationZoneId: getRecordFieldStringValue(FieldReservationZoneId, fieldIndexes, record),
FieldReservationZoneName: getRecordFieldStringValue(FieldReservationZoneName, fieldIndexes, record),
FieldReservationProductName: getRecordFieldStringValue(FieldReservationProductName, fieldIndexes, record),
FieldReservationQuantity: getRecordFieldStringValue(FieldReservationQuantity, fieldIndexes, record),
FieldReservationPurchaseDate: getRecordFieldStringValue(FieldReservationPurchaseDate, fieldIndexes, record),
FieldReservationExpirationDate: getRecordFieldStringValue(FieldReservationExpirationDate, fieldIndexes, record),
FieldReservationType: getRecordFieldStringValue(FieldReservationType, fieldIndexes, record),
FieldReservationDeepLinkToReservation: getRecordFieldStringValue(FieldReservationDeepLinkToReservation, fieldIndexes, record),
FieldReservationRegion: GetRecordFieldStringValue(FieldReservationRegion, fieldIndexes, record),
FieldReservationInstanceType: GetRecordFieldStringValue(FieldReservationInstanceType, fieldIndexes, record),
FieldReservationPrice: GetRecordFieldStringValue(FieldReservationPrice, fieldIndexes, record),
FieldReservationCount: GetRecordFieldStringValue(FieldReservationCount, fieldIndexes, record),
FieldReservationStartDate: GetRecordFieldStringValue(FieldReservationStartDate, fieldIndexes, record),
FieldReservationEndDate: GetRecordFieldStringValue(FieldReservationEndDate, fieldIndexes, record),
FieldReservationZoneId: GetRecordFieldStringValue(FieldReservationZoneId, fieldIndexes, record),
FieldReservationZoneName: GetRecordFieldStringValue(FieldReservationZoneName, fieldIndexes, record),
FieldReservationProductName: GetRecordFieldStringValue(FieldReservationProductName, fieldIndexes, record),
FieldReservationQuantity: GetRecordFieldStringValue(FieldReservationQuantity, fieldIndexes, record),
FieldReservationPurchaseDate: GetRecordFieldStringValue(FieldReservationPurchaseDate, fieldIndexes, record),
FieldReservationExpirationDate: GetRecordFieldStringValue(FieldReservationExpirationDate, fieldIndexes, record),
FieldReservationType: GetRecordFieldStringValue(FieldReservationType, fieldIndexes, record),
FieldReservationDeepLinkToReservation: GetRecordFieldStringValue(FieldReservationDeepLinkToReservation, fieldIndexes, record),
}, nil
}

func getRecordReservationProvider(fieldIndexes map[string]int, record []string) (*string, error) {
provider := getRecordFieldStringValue(FieldReservationProvider, fieldIndexes, record)
func GetRecordReservationProvider(fieldIndexes map[string]int, record []string) (*string, error) {
provider := GetRecordFieldStringValue(FieldReservationProvider, fieldIndexes, record)
if provider != nil && *provider != "" {
return provider, nil
}

deepLinkToReservation := getRecordFieldStringValue(FieldReservationDeepLinkToReservation, fieldIndexes, record)
deepLinkToReservation := GetRecordFieldStringValue(FieldReservationDeepLinkToReservation, fieldIndexes, record)
if deepLinkToReservation != nil && strings.Contains(*deepLinkToReservation, "azure") {
return lo.ToPtr("azure"), nil
}

return nil, fmt.Errorf("reservation provider could not be determined: %v", record)
}

func getRecordFieldStringValue(field string, fieldIndexes map[string]int, record []string) *string {
func GetRecordFieldStringValue(field string, fieldIndexes map[string]int, record []string) *string {
index, found := fieldIndexes[field]
if !found || index == -1 {
return nil
Expand Down
4 changes: 2 additions & 2 deletions castai/reservations/mapping_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ func Test_mapReservationsHeaderToReservationFieldIndexes(t *testing.T) {
t.Run(testName, func(t *testing.T) {
r := require.New(t)

got := mapReservationsHeaderToReservationFieldIndexes(tt.args.columns)
got := MapReservationsHeaderToReservationFieldIndexes(tt.args.columns)

r.Equal(tt.want, got)
})
Expand Down Expand Up @@ -401,7 +401,7 @@ func Test_getRecordReservationProvider(t *testing.T) {
t.Run(testName, func(t *testing.T) {
r := require.New(t)

got, err := getRecordReservationProvider(tt.args.fieldIndexes, tt.args.record)
got, err := GetRecordReservationProvider(tt.args.fieldIndexes, tt.args.record)

if tt.expectErrMessageContains != nil {
r.Error(err)
Expand Down
Loading
Loading