Skip to content

Commit 49c5fe0

Browse files
committed
Implement reconciliation of category for create/update/delete categories, create controller that makes client connection using ProviderConfig credentials.
1 parent 894d9e4 commit 49c5fe0

File tree

11 files changed

+99
-44
lines changed

11 files changed

+99
-44
lines changed

apis/category/v1alpha1/category_types.go

+1-7
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,7 @@ type CategoryParameters struct {
5050

5151
// CategoryObservation are the observable fields of a Category.
5252
type CategoryObservation struct {
53-
ID int `json:"id,omitempty"`
54-
ParentID int `json:"parent_id,omitempty"`
55-
Name string `json:"name,omitempty"`
56-
IsActive bool `json:"is_active,omitempty"`
57-
Position int `json:"position,omitempty"`
58-
Level int `json:"level,omitempty"`
59-
ProductCount int `json:"product_count,omitempty"`
53+
Status string `json:"status,omitempty"`
6054
}
6155

6256
// A CategorySpec defines the desired state of a Category.

apis/v1alpha1/providerconfig_types.go

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import (
2727

2828
// A ProviderConfigSpec defines the desired state of a ProviderConfig.
2929
type ProviderConfigSpec struct {
30+
Scheme string `json:"scheme"`
31+
HostName string `json:"hostName"`
3032
// Credentials required to authenticate to this provider.
3133
Credentials ProviderCredentials `json:"credentials"`
3234
}

examples/provider/config.yaml

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
apiVersion: v1
22
kind: Secret
33
metadata:
4-
namespace: crossplane-system
4+
namespace: default
55
name: example-provider-secret
66
type: Opaque
77
data:
8-
# credentials: BASE64ENCODED_PROVIDER_CREDS
8+
creds: ""
99
---
10-
apiVersion: magento.crossplane.io/v1alpha1
10+
apiVersion: magento.web7.md/v1alpha1
1111
kind: ProviderConfig
1212
metadata:
13-
name: example
13+
name: category-provider-config
1414
spec:
15+
hostName: ""
16+
scheme: ""
1517
credentials:
1618
source: Secret
1719
secretRef:
18-
namespace: crossplane-system
20+
namespace: default
1921
name: example-provider-secret
20-
key: credentials
22+
key: creds

examples/sample/category.yaml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
apiVersion: category.magento.web7.md/v1alpha1
2+
kind: Category
3+
metadata:
4+
name: test-category
5+
spec:
6+
forProvider:
7+
name: "test category"
8+
providerConfigRef:
9+
name: category-provider-config

examples/sample/mytype.yaml

-9
This file was deleted.

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ require (
66
github.com/crossplane/crossplane-runtime v1.14.0-rc.0.0.20230815060607-4f3cb3d9fd2b
77
github.com/crossplane/crossplane-tools v0.0.0-20230714144037-2684f4bc7638
88
github.com/google/go-cmp v0.5.9
9+
github.com/hermsi1337/go-magento2 v0.1.2
910
github.com/pkg/errors v0.9.1
1011
gopkg.in/alecthomas/kingpin.v2 v2.2.6
1112
k8s.io/apimachinery v0.27.4
@@ -74,6 +75,7 @@ require (
7475
google.golang.org/grpc v1.57.0 // indirect
7576
google.golang.org/protobuf v1.31.0 // indirect
7677
gopkg.in/inf.v0 v0.9.1 // indirect
78+
gopkg.in/resty.v1 v1.12.0 // indirect
7779
gopkg.in/yaml.v2 v2.4.0 // indirect
7880
gopkg.in/yaml.v3 v3.0.1 // indirect
7981
k8s.io/api v0.27.4 // indirect

go.sum

+5
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8
186186
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
187187
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
188188
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
189+
github.com/hermsi1337/go-magento2 v0.1.2 h1:fqpzDbbdvJEDICvCkNyk6dVJIlKqjBqq+TJnae/oR+g=
190+
github.com/hermsi1337/go-magento2 v0.1.2/go.mod h1:W6InSIHSfuwc8rravT6N10Vm7VA2qtncnF1wlPMDVnU=
189191
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
190192
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
191193
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
@@ -338,6 +340,7 @@ golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
338340
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
339341
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
340342
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
343+
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
341344
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
342345
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
343346
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -627,6 +630,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
627630
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
628631
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
629632
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
633+
gopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI=
634+
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
630635
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
631636
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
632637
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

internal/controller/category/category.go

+64-8
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ package category
1919
import (
2020
"context"
2121
"fmt"
22+
"strconv"
2223

24+
xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
25+
"github.com/hermsi1337/go-magento2/pkg/magento2/api"
26+
"github.com/hermsi1337/go-magento2/pkg/magento2/categories"
2327
"github.com/pkg/errors"
2428
"k8s.io/apimachinery/pkg/types"
2529
ctrl "sigs.k8s.io/controller-runtime"
@@ -47,10 +51,26 @@ const (
4751
)
4852

4953
// A NoOpService does nothing.
50-
type NoOpService struct{}
54+
type MagentoService struct {
55+
client *api.Client
56+
}
5157

5258
var (
53-
newNoOpService = func(_ []byte) (interface{}, error) { return &NoOpService{}, nil }
59+
newMagentoService = func(creds []byte, scheme string, hostname string) (*MagentoService, error) {
60+
storeConfig := &api.StoreConfig{
61+
Scheme: scheme,
62+
HostName: hostname,
63+
StoreCode: "default",
64+
}
65+
// Create a new Magento API client
66+
c, err := api.NewAPIClientFromIntegration(storeConfig, string(creds))
67+
if err != nil {
68+
return nil, err
69+
}
70+
return &MagentoService{
71+
client: c,
72+
}, nil
73+
}
5474
)
5575

5676
// Setup adds a controller that reconciles Category managed resources.
@@ -67,7 +87,7 @@ func Setup(mgr ctrl.Manager, o controller.Options) error {
6787
managed.WithExternalConnecter(&connector{
6888
kube: mgr.GetClient(),
6989
usage: resource.NewProviderConfigUsageTracker(mgr.GetClient(), &apisv1alpha1.ProviderConfigUsage{}),
70-
newServiceFn: newNoOpService}),
90+
newServiceFn: newMagentoService}),
7191
managed.WithLogger(o.Logger.WithValues("controller", name)),
7292
managed.WithPollInterval(o.PollInterval),
7393
managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))),
@@ -86,7 +106,7 @@ func Setup(mgr ctrl.Manager, o controller.Options) error {
86106
type connector struct {
87107
kube client.Client
88108
usage resource.Tracker
89-
newServiceFn func(creds []byte) (interface{}, error)
109+
newServiceFn func(creds []byte, scheme string, hostname string) (*MagentoService, error)
90110
}
91111

92112
// Connect typically produces an ExternalClient by:
@@ -115,7 +135,7 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E
115135
return nil, errors.Wrap(err, errGetCreds)
116136
}
117137

118-
svc, err := c.newServiceFn(data)
138+
svc, err := c.newServiceFn(data, pc.Spec.Scheme, pc.Spec.HostName)
119139
if err != nil {
120140
return nil, errors.Wrap(err, errNewClient)
121141
}
@@ -128,7 +148,7 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E
128148
type external struct {
129149
// A 'client' used to connect to the external resource API. In practice this
130150
// would be something like an AWS SDK client.
131-
service interface{}
151+
service *MagentoService
132152
}
133153

134154
func (c *external) Observe(ctx context.Context, mg resource.Managed) (managed.ExternalObservation, error) {
@@ -137,6 +157,16 @@ func (c *external) Observe(ctx context.Context, mg resource.Managed) (managed.Ex
137157
return managed.ExternalObservation{}, errors.New(errNotCategory)
138158
}
139159

160+
_, err := categories.GetCategoryByName(cr.Spec.ForProvider.Name, c.service.client)
161+
if err != nil {
162+
return managed.ExternalObservation{
163+
ResourceExists: false,
164+
}, nil
165+
}
166+
167+
if cr.Status.AtProvider.Status == "Ready" {
168+
cr.Status.SetConditions(xpv1.Available())
169+
}
140170
// These fmt statements should be removed in the real implementation.
141171
fmt.Printf("Observing: %+v", cr)
142172

@@ -164,12 +194,20 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext
164194
}
165195

166196
fmt.Printf("Creating: %+v", cr)
197+
_, err := categories.CreateCategory(&categories.Category{
198+
Name: cr.Spec.ForProvider.Name,
199+
IsActive: true,
200+
}, c.service.client)
201+
if err != nil {
202+
return managed.ExternalCreation{}, err
203+
}
204+
cr.Status.AtProvider.Status = "Ready"
167205

168206
return managed.ExternalCreation{
169207
// Optionally return any details that may be required to connect to the
170208
// external resource. These will be stored as the connection secret.
171209
ConnectionDetails: managed.ConnectionDetails{},
172-
}, nil
210+
}, err
173211
}
174212

175213
func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.ExternalUpdate, error) {
@@ -178,6 +216,15 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext
178216
return managed.ExternalUpdate{}, errors.New(errNotCategory)
179217
}
180218

219+
mCategory, err := categories.GetCategoryByName(cr.Spec.ForProvider.Name, c.service.client)
220+
if err != nil {
221+
fmt.Printf("Failed to retrieve category: %v\n", err)
222+
}
223+
url := fmt.Sprintf("/categories/%s", strconv.Itoa(mCategory.Category.ID))
224+
_, err = c.service.client.HTTPClient.R().Put(url)
225+
if err != nil {
226+
fmt.Printf("Failed to update category: %v\n", err)
227+
}
181228
fmt.Printf("Updating: %+v", cr)
182229

183230
return managed.ExternalUpdate{
@@ -192,7 +239,16 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) error {
192239
if !ok {
193240
return errors.New(errNotCategory)
194241
}
195-
242+
mCategory, err := categories.GetCategoryByName(cr.Spec.ForProvider.Name, c.service.client)
243+
if err != nil {
244+
fmt.Printf("Failed to retrieve category: %v\n", err)
245+
}
246+
url := fmt.Sprintf("/categories/%s", strconv.Itoa(mCategory.Category.ID))
247+
_, err = c.service.client.HTTPClient.R().Delete(url)
248+
if err != nil {
249+
fmt.Printf("Failed to delete category: %v\n", err)
250+
return err
251+
}
196252
fmt.Printf("Deleting: %+v", cr)
197253

198254
return nil

internal/controller/category/category_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func TestObserve(t *testing.T) {
6161

6262
for name, tc := range cases {
6363
t.Run(name, func(t *testing.T) {
64-
e := external{service: tc.fields.service}
64+
e := external{service: tc.fields.service.(*MagentoService)}
6565
got, err := e.Observe(tc.args.ctx, tc.args.mg)
6666
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
6767
t.Errorf("\n%s\ne.Observe(...): -want error, +got error:\n%s\n", tc.reason, diff)

package/crds/category.magento.web7.md_categories.yaml

+1-13
Original file line numberDiff line numberDiff line change
@@ -310,20 +310,8 @@ spec:
310310
atProvider:
311311
description: CategoryObservation are the observable fields of a Category.
312312
properties:
313-
id:
314-
type: integer
315-
is_active:
316-
type: boolean
317-
level:
318-
type: integer
319-
name:
313+
status:
320314
type: string
321-
parent_id:
322-
type: integer
323-
position:
324-
type: integer
325-
product_count:
326-
type: integer
327315
type: object
328316
conditions:
329317
description: Conditions of the resource.

package/crds/magento.web7.md_providerconfigs.yaml

+6
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,14 @@ spec:
9595
required:
9696
- source
9797
type: object
98+
hostName:
99+
type: string
100+
scheme:
101+
type: string
98102
required:
99103
- credentials
104+
- hostName
105+
- scheme
100106
type: object
101107
status:
102108
description: A ProviderConfigStatus reflects the observed state of a ProviderConfig.

0 commit comments

Comments
 (0)