1/*
2Copyright (c) 2015 VMware, Inc. All Rights Reserved.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package license
18
19import (
20	"context"
21	"strconv"
22	"strings"
23
24	"github.com/vmware/govmomi/object"
25	"github.com/vmware/govmomi/vim25"
26	"github.com/vmware/govmomi/vim25/methods"
27	"github.com/vmware/govmomi/vim25/mo"
28	"github.com/vmware/govmomi/vim25/types"
29)
30
31type Manager struct {
32	object.Common
33}
34
35func NewManager(c *vim25.Client) *Manager {
36	m := Manager{
37		object.NewCommon(c, *c.ServiceContent.LicenseManager),
38	}
39
40	return &m
41}
42
43func mapToKeyValueSlice(m map[string]string) []types.KeyValue {
44	var r []types.KeyValue
45	for k, v := range m {
46		r = append(r, types.KeyValue{Key: k, Value: v})
47	}
48	return r
49}
50
51func (m Manager) Add(ctx context.Context, key string, labels map[string]string) (types.LicenseManagerLicenseInfo, error) {
52	req := types.AddLicense{
53		This:       m.Reference(),
54		LicenseKey: key,
55		Labels:     mapToKeyValueSlice(labels),
56	}
57
58	res, err := methods.AddLicense(ctx, m.Client(), &req)
59	if err != nil {
60		return types.LicenseManagerLicenseInfo{}, err
61	}
62
63	return res.Returnval, nil
64}
65
66func (m Manager) Decode(ctx context.Context, key string) (types.LicenseManagerLicenseInfo, error) {
67	req := types.DecodeLicense{
68		This:       m.Reference(),
69		LicenseKey: key,
70	}
71
72	res, err := methods.DecodeLicense(ctx, m.Client(), &req)
73	if err != nil {
74		return types.LicenseManagerLicenseInfo{}, err
75	}
76
77	return res.Returnval, nil
78}
79
80func (m Manager) Remove(ctx context.Context, key string) error {
81	req := types.RemoveLicense{
82		This:       m.Reference(),
83		LicenseKey: key,
84	}
85
86	_, err := methods.RemoveLicense(ctx, m.Client(), &req)
87	return err
88}
89
90func (m Manager) Update(ctx context.Context, key string, labels map[string]string) (types.LicenseManagerLicenseInfo, error) {
91	req := types.UpdateLicense{
92		This:       m.Reference(),
93		LicenseKey: key,
94		Labels:     mapToKeyValueSlice(labels),
95	}
96
97	res, err := methods.UpdateLicense(ctx, m.Client(), &req)
98	if err != nil {
99		return types.LicenseManagerLicenseInfo{}, err
100	}
101
102	return res.Returnval, nil
103}
104
105func (m Manager) List(ctx context.Context) (InfoList, error) {
106	var mlm mo.LicenseManager
107
108	err := m.Properties(ctx, m.Reference(), []string{"licenses"}, &mlm)
109	if err != nil {
110		return nil, err
111	}
112
113	return InfoList(mlm.Licenses), nil
114}
115
116func (m Manager) AssignmentManager(ctx context.Context) (*AssignmentManager, error) {
117	var mlm mo.LicenseManager
118
119	err := m.Properties(ctx, m.Reference(), []string{"licenseAssignmentManager"}, &mlm)
120	if err != nil {
121		return nil, err
122	}
123
124	if mlm.LicenseAssignmentManager == nil {
125		return nil, object.ErrNotSupported
126	}
127
128	am := AssignmentManager{
129		object.NewCommon(m.Client(), *mlm.LicenseAssignmentManager),
130	}
131
132	return &am, nil
133}
134
135type licenseFeature struct {
136	name  string
137	level int
138}
139
140func parseLicenseFeature(feature string) *licenseFeature {
141	lf := new(licenseFeature)
142
143	f := strings.Split(feature, ":")
144
145	lf.name = f[0]
146
147	if len(f) > 1 {
148		var err error
149		lf.level, err = strconv.Atoi(f[1])
150		if err != nil {
151			lf.name = feature
152		}
153	}
154
155	return lf
156}
157
158func HasFeature(license types.LicenseManagerLicenseInfo, key string) bool {
159	feature := parseLicenseFeature(key)
160
161	for _, p := range license.Properties {
162		if p.Key != "feature" {
163			continue
164		}
165
166		kv, ok := p.Value.(types.KeyValue)
167
168		if !ok {
169			continue
170		}
171
172		lf := parseLicenseFeature(kv.Key)
173
174		if lf.name == feature.name && lf.level >= feature.level {
175			return true
176		}
177	}
178
179	return false
180}
181
182// InfoList provides helper methods for []types.LicenseManagerLicenseInfo
183type InfoList []types.LicenseManagerLicenseInfo
184
185func (l InfoList) WithFeature(key string) InfoList {
186	var result InfoList
187
188	for _, license := range l {
189		if HasFeature(license, key) {
190			result = append(result, license)
191		}
192	}
193
194	return result
195}
196