Skip to content

Commit 242270d

Browse files
authored
Wire Up Identity Provisioner (#6)
1 parent 84b4fa7 commit 242270d

File tree

13 files changed

+375
-236
lines changed

13 files changed

+375
-236
lines changed

charts/region/Chart.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: A Helm chart for deploying Unikorn's Region Controller
44

55
type: application
66

7-
version: v0.1.1
8-
appVersion: v0.1.1
7+
version: v0.1.2
8+
appVersion: v0.1.2
99

1010
icon: https://raw.githubusercontent.com/unikorn-cloud/unikorn/main/icons/default.png
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
---
2+
apiVersion: apiextensions.k8s.io/v1
3+
kind: CustomResourceDefinition
4+
metadata:
5+
annotations:
6+
controller-gen.kubebuilder.io/version: v0.14.0
7+
name: identities.region.unikorn-cloud.org
8+
spec:
9+
group: region.unikorn-cloud.org
10+
names:
11+
categories:
12+
- unikorn
13+
kind: Identity
14+
listKind: IdentityList
15+
plural: identities
16+
singular: identity
17+
scope: Namespaced
18+
versions:
19+
- additionalPrinterColumns:
20+
- jsonPath: .spec.provider
21+
name: provider
22+
type: string
23+
- jsonPath: .status.conditions[?(@.type=="Available")].reason
24+
name: status
25+
type: string
26+
- jsonPath: .metadata.creationTimestamp
27+
name: age
28+
type: date
29+
name: v1alpha1
30+
schema:
31+
openAPIV3Schema:
32+
description: |-
33+
Identity defines an on-demand cloud identity. The region controller must
34+
create any resources necessary to provide dynamic provisioning of clusters
35+
e.g. compute, storage and networking. This resource is used for persistence
36+
of information by the controller and not for manual lifecycle management.
37+
Any credentials should not be stored unless absolutely necessary, and should
38+
be passed to a client on initial identity creation only.
39+
properties:
40+
apiVersion:
41+
description: |-
42+
APIVersion defines the versioned schema of this representation of an object.
43+
Servers should convert recognized schemas to the latest internal value, and
44+
may reject unrecognized values.
45+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
46+
type: string
47+
kind:
48+
description: |-
49+
Kind is a string value representing the REST resource this object represents.
50+
Servers may infer this from the endpoint the client submits requests to.
51+
Cannot be updated.
52+
In CamelCase.
53+
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
54+
type: string
55+
metadata:
56+
type: object
57+
spec:
58+
description: IdentitySpec stores any state necessary to manage identity.
59+
properties:
60+
openstack:
61+
description: OpenStack is populated when the provider type is set
62+
to "openstack".
63+
properties:
64+
projectID:
65+
description: ProjectIS is the ID of the project created for the
66+
identity.
67+
type: string
68+
userID:
69+
description: UserID is the ID of the user created for the identity.
70+
type: string
71+
required:
72+
- projectID
73+
- userID
74+
type: object
75+
provider:
76+
description: Provider defines the provider type.
77+
enum:
78+
- openstack
79+
type: string
80+
required:
81+
- provider
82+
type: object
83+
status:
84+
type: object
85+
required:
86+
- spec
87+
- status
88+
type: object
89+
served: true
90+
storage: true
91+
subresources: {}

charts/region/templates/region-controller/clusterrole.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ rules:
1313
verbs:
1414
- list
1515
- watch
16+
- apiGroups:
17+
- region.unikorn-cloud.org
18+
resources:
19+
- identities
20+
verbs:
21+
- list
22+
- watch
23+
- create
24+
- delete
1625
- apiGroups:
1726
- ""
1827
resources:

pkg/apis/unikorn/v1alpha1/types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,9 @@ type IdentitySpec struct {
168168

169169
type IdentitySpecOpenStack struct {
170170
// UserID is the ID of the user created for the identity.
171-
UserID string
171+
UserID string `json:"userID"`
172172
// ProjectIS is the ID of the project created for the identity.
173-
ProjectID string
173+
ProjectID string `json:"projectID"`
174174
}
175175

176176
type IdentityStatus struct {

pkg/handler/handler.go

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,19 @@ limitations under the License.
1919
package handler
2020

2121
import (
22+
"cmp"
23+
"encoding/base64"
2224
"fmt"
2325
"net/http"
24-
"sort"
26+
"slices"
2527
"time"
2628

2729
coreopenapi "github.com/unikorn-cloud/core/pkg/openapi"
30+
"github.com/unikorn-cloud/core/pkg/server/conversion"
2831
"github.com/unikorn-cloud/core/pkg/server/errors"
2932
"github.com/unikorn-cloud/core/pkg/server/middleware/openapi/oidc"
3033
coreutil "github.com/unikorn-cloud/core/pkg/util"
34+
unikornv1 "github.com/unikorn-cloud/region/pkg/apis/unikorn/v1alpha1"
3135
"github.com/unikorn-cloud/region/pkg/handler/region"
3236
"github.com/unikorn-cloud/region/pkg/openapi"
3337
"github.com/unikorn-cloud/region/pkg/providers"
@@ -128,8 +132,15 @@ func (h *Handler) GetApiV1RegionsRegionIDFlavors(w http.ResponseWriter, r *http.
128132
return
129133
}
130134

131-
// Apply ordering guarantees.
132-
sort.Stable(result)
135+
// Apply ordering guarantees, ascending order with GPUs taking precedence over
136+
// CPUs.
137+
slices.SortFunc(result, func(a, b providers.Flavor) int {
138+
if v := cmp.Compare(a.GPUs, b.GPUs); v != 0 {
139+
return v
140+
}
141+
142+
return cmp.Compare(a.CPUs, b.CPUs)
143+
})
133144

134145
out := make(openapi.Flavors, len(result))
135146

@@ -173,8 +184,10 @@ func (h *Handler) GetApiV1RegionsRegionIDImages(w http.ResponseWriter, r *http.R
173184
return
174185
}
175186

176-
// Apply ordering guarantees.
177-
sort.Stable(result)
187+
// Apply ordering guarantees, ordered by name.
188+
slices.SortFunc(result, func(a, b providers.Image) int {
189+
return cmp.Compare(a.Name, b.Name)
190+
})
178191

179192
out := make(openapi.Images, len(result))
180193

@@ -186,7 +199,49 @@ func (h *Handler) GetApiV1RegionsRegionIDImages(w http.ResponseWriter, r *http.R
186199
util.WriteJSONResponse(w, r, http.StatusOK, out)
187200
}
188201

202+
func convertCloudConfig(identity *unikornv1.Identity, in *providers.CloudConfig) *openapi.IdentityRead {
203+
out := &openapi.IdentityRead{
204+
Metadata: conversion.ProjectScopedResourceReadMetadata(identity, coreopenapi.ResourceProvisioningStatusProvisioned),
205+
}
206+
207+
switch in.Type {
208+
case providers.ProviderTypeOpenStack:
209+
out.Spec = openapi.IdentitySpec{
210+
Type: openapi.Openstack,
211+
Openstack: &openapi.IdentitySpecOpenStack{
212+
Cloud: in.OpenStack.Credentials.Cloud,
213+
CloudConfig: base64.URLEncoding.EncodeToString(in.OpenStack.Credentials.CloudConfig),
214+
UserId: in.OpenStack.State.UserID,
215+
ProjectId: in.OpenStack.State.ProjectID,
216+
},
217+
}
218+
}
219+
220+
return out
221+
}
222+
189223
func (h *Handler) PostApiV1RegionsRegionIDIdentities(w http.ResponseWriter, r *http.Request, regionID openapi.RegionIDParameter) {
224+
request := &openapi.IdentityWrite{}
225+
226+
if err := util.ReadJSONBody(r, request); err != nil {
227+
errors.HandleError(w, r, err)
228+
return
229+
}
230+
231+
provider, err := region.NewClient(h.client, h.namespace).Provider(r.Context(), regionID)
232+
if err != nil {
233+
errors.HandleError(w, r, err)
234+
return
235+
}
236+
237+
identity, cloudconfig, err := provider.CreateIdentity(r.Context(), &providers.ClusterInfo{})
238+
if err != nil {
239+
errors.HandleError(w, r, err)
240+
return
241+
}
242+
243+
h.setCacheable(w)
244+
util.WriteJSONResponse(w, r, http.StatusCreated, convertCloudConfig(identity, cloudconfig))
190245
}
191246

192247
func (h *Handler) DeleteApiV1RegionsRegionIDIdentitiesIdentityID(w http.ResponseWriter, r *http.Request, regionID openapi.RegionIDParameter, identityID openapi.IdentityIDParameter) {

pkg/openapi/schema.go

Lines changed: 66 additions & 64 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)