generated from SAP/repository-template
/
datasource_subaccount_entitlements.go
208 lines (174 loc) · 8.86 KB
/
datasource_subaccount_entitlements.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
package provider
import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/SAP/terraform-provider-btp/internal/btpcli"
"github.com/SAP/terraform-provider-btp/internal/btpcli/types/cis_entitlements"
"github.com/SAP/terraform-provider-btp/internal/validation/uuidvalidator"
)
func newSubaccountEntitlementsDataSource() datasource.DataSource {
return &subaccountEntitlementsDataSource{}
}
type subaccountEntitlementsDataSourceConfig struct {
/* INPUT */
SubaccountId types.String `tfsdk:"subaccount_id"`
Id types.String `tfsdk:"id"`
/* OUTPUT */
Values types.Map `tfsdk:"values"`
}
type subaccountEntitlementsDataSource struct {
cli *btpcli.ClientFacade
}
func (ds *subaccountEntitlementsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = fmt.Sprintf("%s_subaccount_entitlements", req.ProviderTypeName)
}
func (ds *subaccountEntitlementsDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}
ds.cli = req.ProviderData.(*btpcli.ClientFacade)
}
func (ds *subaccountEntitlementsDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: `Gets all the entitlements and quota assignments for a subaccount.
To get all entitlements and quota assigned to a specific subaccount:
* You must be assigned to either the subaccount admin or subaccount viewer role.`,
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{ // required by hashicorps terraform plugin testing framework
DeprecationMessage: "Use the `subaccount_id` attribute instead",
MarkdownDescription: "The ID of the subaccount.",
Computed: true,
}, "subaccount_id": schema.StringAttribute{
MarkdownDescription: "The ID of the subaccount.",
Required: true,
Validators: []validator.String{
uuidvalidator.ValidUUID(),
},
},
"values": schema.MapNestedAttribute{
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"service_name": schema.StringAttribute{
MarkdownDescription: "The name of the entitled service.",
Computed: true,
},
"service_display_name": schema.StringAttribute{
MarkdownDescription: "The display name of the entitled service.",
Computed: true,
},
"plan_name": schema.StringAttribute{
MarkdownDescription: "The name of the entitled service plan.",
Computed: true,
},
"plan_display_name": schema.StringAttribute{
MarkdownDescription: "The display name of the entitled service plan.",
Computed: true,
},
"plan_description": schema.StringAttribute{
MarkdownDescription: "The description of the entitled service plan.",
Computed: true,
},
"quota_assigned": schema.Float64Attribute{
MarkdownDescription: "The overall quota assigned.",
Computed: true,
},
"quota_remaining": schema.Float64Attribute{
MarkdownDescription: "The quota, which is not used.",
Computed: true,
},
"category": schema.StringAttribute{
MarkdownDescription: "The current state of the entitlement. Possible values are: \n " +
getFormattedValueAsTableRow("value", "description") +
getFormattedValueAsTableRow("---", "---") +
getFormattedValueAsTableRow("`PLATFORM`", " A service required for using a specific platform; for example, Application Runtime is required for the Cloud Foundry platform.") +
getFormattedValueAsTableRow("`SERVICE`", "A commercial or technical service. that has a numeric quota (amount) when entitled or assigned to a resource. When assigning entitlements of this type, use the 'amount' option.") +
getFormattedValueAsTableRow("`ELASTIC_SERVICE`", "A commercial or technical service that has no numeric quota (amount) when entitled or assigned to a resource. Generally this type of service can be as many times as needed when enabled, but may in some cases be restricted by the service owner.") +
getFormattedValueAsTableRow("`ELASTIC_LIMITED`", "An elastic service that can be enabled for only one subaccount per global account.") +
getFormattedValueAsTableRow("`APPLICATION`", "A multitenant application to which consumers can subscribe. As opposed to applications defined as a 'QUOTA_BASED_APPLICATION', these applications do not have a numeric quota and are simply enabled or disabled as entitlements per subaccount.") +
getFormattedValueAsTableRow("`QUOTA_BASED_APPLICATION`", "A multitenant application to which consumers can subscribe. As opposed to applications defined as 'APPLICATION', these applications have an numeric quota that limits consumer usage of the subscribed application per subaccount.") +
getFormattedValueAsTableRow("`ENVIRONMENT`", " An environment service; for example, Cloud Foundry."),
Computed: true,
},
},
},
Computed: true,
},
},
}
}
func (ds *subaccountEntitlementsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data subaccountEntitlementsDataSourceConfig
var cliRes cis_entitlements.EntitledAndAssignedServicesResponseObject
var err error
diags := req.Config.Get(ctx, &data)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
// Determine the parent of the subaccount
// In case of a directory with feature "ENTITLEMENTS" enabled we must hand over the ID in the "List" call
subaccountData, _, _ := ds.cli.Accounts.Subaccount.Get(ctx, data.SubaccountId.ValueString())
parentId, isParentGlobalAccount := determineParentIdForEntitlement(ds.cli, ctx, subaccountData.ParentGUID)
if isParentGlobalAccount {
cliRes, _, err = ds.cli.Accounts.Entitlement.ListBySubaccount(ctx, data.SubaccountId.ValueString())
} else {
cliRes, _, err = ds.cli.Accounts.Entitlement.ListBySubaccountWithDirectoryParent(ctx, data.SubaccountId.ValueString(), parentId)
}
if err != nil {
resp.Diagnostics.AddError("API Error Reading Resource Entitlements (Subaccount)", fmt.Sprintf("%s", err))
return
}
values := map[string]entitledService{}
// For subaccounts the relevant information is in the "AssignedServices" section - especially the quota information
for _, service := range cliRes.AssignedServices {
entitledServiceFromList := determineServiceFromEntitledList(service.Name, cliRes.EntitledServices)
for _, servicePlan := range service.ServicePlans {
assignedQuota, remainingQuota := calculateQuotaValues(servicePlan.AssignmentInfo)
servicePlanDescription := determineServicePlanDescription(servicePlan.Name, servicePlan.DisplayName, entitledServiceFromList.ServicePlans)
values[fmt.Sprintf("%s:%s", service.Name, servicePlan.Name)] = entitledService{
ServiceName: types.StringValue(service.Name),
ServiceDisplayName: types.StringValue(service.DisplayName),
PlanName: types.StringValue(servicePlan.Name),
PlanDisplayName: types.StringValue(servicePlan.DisplayName),
PlanDescription: types.StringValue(servicePlanDescription),
QuotaAssigned: types.Float64Value(assignedQuota),
QuotaRemaining: types.Float64Value(remainingQuota),
Category: types.StringValue(servicePlan.Category),
}
}
}
data.Id = data.SubaccountId
data.Values, diags = types.MapValueFrom(ctx, types.ObjectType{AttrTypes: entitledServiceType()}, values)
resp.Diagnostics.Append(diags...)
diags = resp.State.Set(ctx, &data)
resp.Diagnostics.Append(diags...)
}
func calculateQuotaValues(assignmentInformation []cis_entitlements.AssignedServicePlanSubaccountDto) (assignedQuota float64, remainingQuota float64) {
for _, assignment := range assignmentInformation {
assignedQuota += assignment.Amount
remainingQuota += assignment.ParentRemainingAmount
}
return
}
func determineServicePlanDescription(servicePlanName string, servicePlanDisplayName string, servicePlans []cis_entitlements.ServicePlanResponseObject) (servicePlanDescription string) {
servicePlanDescription = servicePlanDisplayName
for _, servicePlan := range servicePlans {
if servicePlan.Name == servicePlanName {
servicePlanDescription = servicePlan.Description
return
}
}
return
}
func determineServiceFromEntitledList(serviceName string, serviceEntitlements []cis_entitlements.EntitledServicesResponseObject) (entitledService cis_entitlements.EntitledServicesResponseObject) {
for _, service := range serviceEntitlements {
if service.Name == serviceName {
return service
}
}
return
}