diff --git a/examples/platform_stack/main.tf b/examples/platform_stack/main.tf index 8e1a913..f8e8e18 100644 --- a/examples/platform_stack/main.tf +++ b/examples/platform_stack/main.tf @@ -206,49 +206,271 @@ resource "kaleido_platform_service" "ams_0" { }) } -resource "kaleido_platform_cms_build" "contract_0" { +resource "kaleido_platform_cms_build" "erc20" { environment = kaleido_platform_environment.env_0.id service = kaleido_platform_service.cms_0.id type = "github" - name = "ff" - path = "firefly" + name = "ERC20WithData" + path = "erc20_samples" github = { - contract_url = "https://github.com/hyperledger/firefly/blob/main/smart_contracts/ethereum/solidity_firefly/contracts/Firefly.sol" - contract_name = "Firefly" + contract_url = "https://github.com/hyperledger/firefly-tokens-erc20-erc721/blob/main/samples/solidity/contracts/ERC20WithData.sol" + contract_name = "ERC20WithData" } } -resource "kaleido_platform_cms_action_deploy" "deploy_0" { +resource "kaleido_platform_cms_build" "erc721" { environment = kaleido_platform_environment.env_0.id service = kaleido_platform_service.cms_0.id - build = kaleido_platform_cms_build.contract_0.id - name = "deploy_0" + type = "github" + name = "ERC721WithData" + path = "erc721_samples" + github = { + contract_url = "https://github.com/hyperledger/firefly-tokens-erc20-erc721/blob/main/samples/solidity/contracts/ERC721WithData.sol" + contract_name = "ERC721WithData" + } + depends_on = [ kaleido_platform_cms_build.erc20 ] // don't compile in parallel (excessive disk usage for npm) +} + +resource "kaleido_platform_cms_action_deploy" "demotoken_erc20" { + environment = kaleido_platform_environment.env_0.id + service = kaleido_platform_service.cms_0.id + build = kaleido_platform_cms_build.erc20.id + name = "deploy_erc20" + firefly_namespace = kaleido_platform_service.ffs_0.name + signing_key = kaleido_platform_kms_key.key_0.address + params_json = jsonencode([ + "DemoToken", + "DTOK" + ]) + depends_on = [ data.kaleido_platform_evm_netinfo.gws_0 ] +} + +resource "kaleido_platform_cms_action_deploy" "demotoken_erc721" { + environment = kaleido_platform_environment.env_0.id + service = kaleido_platform_service.cms_0.id + build = kaleido_platform_cms_build.erc721.id + name = "deploy_erc721" firefly_namespace = kaleido_platform_service.ffs_0.name signing_key = kaleido_platform_kms_key.key_0.address + params_json = jsonencode([ + "DemoNFT", + "DNFT", + "demo://token/" + ]) + depends_on = [ data.kaleido_platform_evm_netinfo.gws_0 ] +} + +resource "kaleido_platform_cms_action_creatapi" "erc20" { + environment = kaleido_platform_environment.env_0.id + service = kaleido_platform_service.cms_0.id + build = kaleido_platform_cms_build.erc20.id + name = "erc20withdata" + firefly_namespace = kaleido_platform_service.ffs_0.name + api_name = "erc20withdata" depends_on = [ data.kaleido_platform_evm_netinfo.gws_0 ] } -resource "kaleido_platform_cms_action_creatapi" "api_0" { +resource "kaleido_platform_cms_action_creatapi" "erc721" { environment = kaleido_platform_environment.env_0.id service = kaleido_platform_service.cms_0.id - build = kaleido_platform_cms_build.contract_0.id - name = "api_0" + build = kaleido_platform_cms_build.erc721.id + name = "erc721withdata" firefly_namespace = kaleido_platform_service.ffs_0.name - api_name = "firefly" - contract_address = kaleido_platform_cms_action_deploy.deploy_0.contract_address + api_name = "erc721withdata" depends_on = [ data.kaleido_platform_evm_netinfo.gws_0 ] } -resource "kaleido_platform_ams_task" "task_0" { +resource "kaleido_platform_ams_task" "erc20_indexer" { environment = kaleido_platform_environment.env_0.id service = kaleido_platform_service.ams_0.id task_yaml = <- + [{ + "updateType": "create_or_ignore", + "name": "erc721_" & input.blockchainEvent.info.address + }] + assets: >- + [{ + "updateType": "create_or_update", + "collection": "erc721_" & input.blockchainEvent.info.address, + "name": "erc721_" & input.blockchainEvent.info.address & "_" & input.blockchainEvent.output.tokenId + }] + nfts: >- + [{ + "updateType": "create_or_ignore", + "asset": "erc721_" & input.blockchainEvent.info.address & "_" & input.blockchainEvent.output.tokenId, + "name": "erc721", + "standard": "ERC-721", + "address": input.blockchainEvent.info.address, + "tokenIndex": input.blockchainEvent.output.tokenId, + "uri": steps.query_uri.data.output + }] + transfers: >- + [{ + "protocolId": input.blockchainEvent.protocolId, + "asset": "erc721_" & input.blockchainEvent.info.address & "_" & input.blockchainEvent.output.tokenId, + "from": input.blockchainEvent.output.from, + "to": input.blockchainEvent.output.to, + "amount": "1", + "transactionHash": input.blockchainEvent.info.transactionHash, + "parent": { + "type": "nft", + "ref": "erc721" + } + }] + name: upsert_transfer + options: {} + skip: |- + input.blockchainEvent.info.signature != + "Transfer(address,address,uint256)" or + $boolean([input.blockchainEvent.output.tokenId]) = false + type: data_model_update EOT +} + +resource "kaleido_platform_ams_fflistener" "erc721_indexer" { + environment = kaleido_platform_environment.env_0.id + service = kaleido_platform_service.ams_0.id + name = "erc721_indexer" + config_json = jsonencode({ + namespace = kaleido_platform_service.ffs_0.name, + taskName = "erc721_indexer", + blockchainEvents = { + createOptions = { + firstEvent = "0" + }, + abiEvents = [ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "tokenId", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + } + ] + } + }) } \ No newline at end of file diff --git a/examples/platform_stack/variables.tf b/examples/platform_stack/variables.tf index 11ffc3b..a066288 100644 --- a/examples/platform_stack/variables.tf +++ b/examples/platform_stack/variables.tf @@ -16,4 +16,5 @@ variable "environment_name" { variable "node_count" { type = number + default = 1 } diff --git a/kaleido/platform/ams_fflistener.go b/kaleido/platform/ams_fflistener.go new file mode 100644 index 0000000..9004d95 --- /dev/null +++ b/kaleido/platform/ams_fflistener.go @@ -0,0 +1,176 @@ +// Copyright © Kaleido, Inc. 2024 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package platform + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +type AMSFFListenerResourceModel struct { + ID types.String `tfsdk:"id"` + Environment types.String `tfsdk:"environment"` + Service types.String `tfsdk:"service"` + Name types.String `tfsdk:"name"` + Disabled types.Bool `tfsdk:"disabled"` + ConfigJSON types.String `tfsdk:"config_json"` +} + +type AMSFFListenerAPIModel struct { + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Created string `json:"created,omitempty"` + Updated string `json:"updated,omitempty"` + Disabled bool `json:"disabled"` + Config interface{} `json:"config,omitempty"` +} + +func AMSFFListenerResourceFactory() resource.Resource { + return &ams_fflistenerResource{} +} + +type ams_fflistenerResource struct { + commonResource +} + +func (r *ams_fflistenerResource) Metadata(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "kaleido_platform_ams_fflistener" +} + +func (r *ams_fflistenerResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": &schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + }, + "environment": &schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "service": &schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "name": &schema.StringAttribute{ + Required: true, + }, + "disabled": &schema.BoolAttribute{ + Optional: true, + Computed: true, + Default: booldefault.StaticBool(false), + }, + "config_json": &schema.StringAttribute{ + Required: true, + }, + }, + } +} + +func (data *AMSFFListenerResourceModel) toAPI(api *AMSFFListenerAPIModel, diagnostics *diag.Diagnostics) bool { + api.Name = data.Name.ValueString() + api.Disabled = data.Disabled.ValueBool() + err := json.Unmarshal([]byte(data.ConfigJSON.ValueString()), &api.Config) + if err != nil { + diagnostics.AddError("failed to serialize config JSON", err.Error()) + return false + } + return true +} + +func (api *AMSFFListenerAPIModel) toData(data *AMSFFListenerResourceModel) { + data.ID = types.StringValue(api.ID) + data.Disabled = types.BoolValue(api.Disabled) +} + +func (r *ams_fflistenerResource) apiPath(data *AMSFFListenerResourceModel, idOrName string) string { + return fmt.Sprintf("/endpoint/%s/%s/rest/api/v1/listeners/firefly/%s", data.Environment.ValueString(), data.Service.ValueString(), idOrName) +} + +func (r *ams_fflistenerResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + + var data AMSFFListenerResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + var api AMSFFListenerAPIModel + ok := data.toAPI(&api, &resp.Diagnostics) + if ok { + ok, _ = r.apiRequest(ctx, http.MethodPut, r.apiPath(&data, data.Name.ValueString()), &api, &api, &resp.Diagnostics) + } + if !ok { + return + } + + api.toData(&data) + resp.Diagnostics.Append(resp.State.Set(ctx, data)...) + +} + +func (r *ams_fflistenerResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + + var data AMSFFListenerResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + resp.Diagnostics.Append(req.State.GetAttribute(ctx, path.Root("id"), &data.ID)...) + + var api AMSFFListenerAPIModel + ok := data.toAPI(&api, &resp.Diagnostics) + if ok { + ok, _ = r.apiRequest(ctx, http.MethodPut, r.apiPath(&data, data.ID.ValueString()), &api, &api, &resp.Diagnostics) + } + if !ok { + return + } + + api.toData(&data) + resp.Diagnostics.Append(resp.State.Set(ctx, data)...) +} + +func (r *ams_fflistenerResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data AMSFFListenerResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + var api AMSFFListenerAPIModel + api.ID = data.ID.ValueString() + ok, status := r.apiRequest(ctx, http.MethodGet, r.apiPath(&data, data.ID.ValueString()), nil, &api, &resp.Diagnostics, Allow404()) + if !ok { + return + } + if status == 404 { + resp.State.RemoveResource(ctx) + return + } + + api.toData(&data) + resp.Diagnostics.Append(resp.State.Set(ctx, data)...) +} + +func (r *ams_fflistenerResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data AMSFFListenerResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + _, _ = r.apiRequest(ctx, http.MethodDelete, r.apiPath(&data, data.ID.ValueString()), nil, nil, &resp.Diagnostics, Allow404()) + + r.waitForRemoval(ctx, r.apiPath(&data, data.ID.ValueString()), &resp.Diagnostics) +} diff --git a/kaleido/platform/ams_fflistener_test.go b/kaleido/platform/ams_fflistener_test.go new file mode 100644 index 0000000..87f2c8f --- /dev/null +++ b/kaleido/platform/ams_fflistener_test.go @@ -0,0 +1,192 @@ +// Copyright © Kaleido, Inc. 2024 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package platform + +import ( + "fmt" + "net/http" + "testing" + "time" + + "github.com/aidarkhanov/nanoid" + "github.com/gorilla/mux" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/stretchr/testify/assert" + + _ "embed" +) + +var ams_fflistenerStep1 = ` +resource "kaleido_platform_ams_fflistener" "ams_fflistener1" { + environment = "env1" + service = "service1" + name = "listener1" + config_json = jsonencode({ + firstEvent = "0", + namespace = "ns1", + taskName = "task1", + blockchainEvents = { + abiEvents = [ + { + name = "event1" + } + ], + locations = [ + { + address = "0x123456" + } + ] + } + }) +} +` + +var ams_fflistenerStep2 = ` +resource "kaleido_platform_ams_fflistener" "ams_fflistener1" { + environment = "env1" + service = "service1" + name = "listener1" + disabled = true + config_json = jsonencode({ + firstEvent = "0", + namespace = "ns1", + taskName = "task1", + taskVersion = "2024.01.02", + blockchainEvents = { + abiEvents = [ + { + name = "event1" + } + ], + locations = [ + { + address = "0x123456" + } + ] + } + }) + +} +` + +func TestAMSFFListener1(t *testing.T) { + + mp, providerConfig := testSetup(t) + defer func() { + mp.checkClearCalls([]string{ + "PUT /endpoint/{env}/{service}/rest/api/v1/listeners/firefly/{listener}", // by name initially + "GET /endpoint/{env}/{service}/rest/api/v1/listeners/firefly/{listener}", + "GET /endpoint/{env}/{service}/rest/api/v1/listeners/firefly/{listener}", + "PUT /endpoint/{env}/{service}/rest/api/v1/listeners/firefly/{listener}", // then by ID + "GET /endpoint/{env}/{service}/rest/api/v1/listeners/firefly/{listener}", + "DELETE /endpoint/{env}/{service}/rest/api/v1/listeners/firefly/{listener}", + "GET /endpoint/{env}/{service}/rest/api/v1/listeners/firefly/{listener}", + }) + mp.server.Close() + }() + + ams_fflistener1Resource := "kaleido_platform_ams_fflistener.ams_fflistener1" + resource.Test(t, resource.TestCase{ + IsUnitTest: true, + ProtoV6ProviderFactories: testAccProviders, + Steps: []resource.TestStep{ + { + Config: providerConfig + ams_fflistenerStep1, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet(ams_fflistener1Resource, "id"), + resource.TestCheckResourceAttr(ams_fflistener1Resource, "disabled", "false"), + ), + }, + { + Config: providerConfig + ams_fflistenerStep2, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet(ams_fflistener1Resource, "id"), + resource.TestCheckResourceAttr(ams_fflistener1Resource, "disabled", "true"), + func(s *terraform.State) error { + // Compare the final result on the mock-server side + id := s.RootModule().Resources[ams_fflistener1Resource].Primary.Attributes["id"] + obj := mp.amsFFListeners[fmt.Sprintf("env1/service1/%s", id)] + testYAMLEqual(t, obj, fmt.Sprintf(`{ + "id": "%[1]s", + "created": "%[2]s", + "updated": "%[3]s", + "name": "listener1", + "disabled": true, + "config": { + "blockchainEvents": { + "abiEvents": [ + { + "name": "event1" + } + ], + "locations": [ + { + "address": "0x123456" + } + ] + }, + "firstEvent": "0", + "namespace": "ns1", + "taskName": "task1", + "taskVersion": "2024.01.02" + } + }`, + // generated fields that vary per test run + id, + obj.Created, + obj.Updated, + )) + return nil + }, + ), + }, + }, + }) +} + +func (mp *mockPlatform) getAMSFFListener(res http.ResponseWriter, req *http.Request) { + obj := mp.amsFFListeners[mux.Vars(req)["env"]+"/"+mux.Vars(req)["service"]+"/"+mux.Vars(req)["listener"]] + if obj == nil { + mp.respond(res, nil, 404) + } else { + mp.respond(res, obj, 200) + } +} + +func (mp *mockPlatform) putAMSFFListener(res http.ResponseWriter, req *http.Request) { + now := time.Now().UTC() + obj := mp.amsFFListeners[mux.Vars(req)["env"]+"/"+mux.Vars(req)["service"]+"/"+mux.Vars(req)["listener"]] // expected behavior of provider is PUT only on exists + var newObj AMSFFListenerAPIModel + mp.getBody(req, &newObj) + if obj == nil { + assert.Equal(mp.t, newObj.Name, mux.Vars(req)["listener"]) + newObj.ID = nanoid.New() + newObj.Created = now.Format(time.RFC3339Nano) + } else { + assert.Equal(mp.t, obj.ID, mux.Vars(req)["listener"]) + newObj.ID = mux.Vars(req)["listener"] + newObj.Created = obj.Created + } + newObj.Updated = now.Format(time.RFC3339Nano) + mp.amsFFListeners[mux.Vars(req)["env"]+"/"+mux.Vars(req)["service"]+"/"+newObj.ID] = &newObj + mp.respond(res, &newObj, 200) +} + +func (mp *mockPlatform) deleteAMSFFListener(res http.ResponseWriter, req *http.Request) { + obj := mp.amsFFListeners[mux.Vars(req)["env"]+"/"+mux.Vars(req)["service"]+"/"+mux.Vars(req)["listener"]] + assert.NotNil(mp.t, obj) + delete(mp.amsFFListeners, mux.Vars(req)["env"]+"/"+mux.Vars(req)["service"]+"/"+mux.Vars(req)["listener"]) + mp.respond(res, nil, 204) +} diff --git a/kaleido/platform/cms_action_deploy.go b/kaleido/platform/cms_action_deploy.go index 80e3ee7..fab16a8 100644 --- a/kaleido/platform/cms_action_deploy.go +++ b/kaleido/platform/cms_action_deploy.go @@ -15,8 +15,10 @@ package platform import ( "context" + "encoding/json" "net/http" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -34,6 +36,7 @@ type CMSActionDeployResourceModel struct { Description types.String `tfsdk:"description"` FireFlyNamespace types.String `tfsdk:"firefly_namespace"` SigningKey types.String `tfsdk:"signing_key"` + ParamsJSON types.String `tfsdk:"params_json"` TransactionID types.String `tfsdk:"transaction_id"` IdempotencyKey types.String `tfsdk:"idempotency_key"` OperationID types.String `tfsdk:"operation_id"` @@ -127,6 +130,10 @@ func (r *cms_action_deployResource) Schema(_ context.Context, _ resource.SchemaR Required: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, }, + "params_json": &schema.StringAttribute{ + Optional: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, "transaction_id": &schema.StringAttribute{ Computed: true, }, @@ -146,7 +153,7 @@ func (r *cms_action_deployResource) Schema(_ context.Context, _ resource.SchemaR } } -func (data *CMSActionDeployResourceModel) toAPI(api *CMSActionDeployAPIModel) { +func (data *CMSActionDeployResourceModel) toAPI(api *CMSActionDeployAPIModel, diagnostics *diag.Diagnostics) bool { api.Type = "deploy" api.Name = data.Name.ValueString() api.Description = data.Description.ValueString() @@ -157,6 +164,14 @@ func (data *CMSActionDeployResourceModel) toAPI(api *CMSActionDeployAPIModel) { }, SingingKey: data.SigningKey.ValueString(), } + if data.ParamsJSON.ValueString() != "" { + err := json.Unmarshal([]byte(data.ParamsJSON.ValueString()), &api.Input.ConstructorParams) + if err != nil { + diagnostics.AddError("failed to serialize params JSON", err.Error()) + return false + } + } + return true } func (api *CMSActionDeployAPIModel) toData(data *CMSActionDeployResourceModel) { @@ -176,8 +191,10 @@ func (r *cms_action_deployResource) Create(ctx context.Context, req resource.Cre resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) var api CMSActionDeployAPIModel - data.toAPI(&api) - ok, _ := r.apiRequest(ctx, http.MethodPost, r.apiPath(&data), api, &api, &resp.Diagnostics) + ok := data.toAPI(&api, &resp.Diagnostics) + if ok { + ok, _ = r.apiRequest(ctx, http.MethodPost, r.apiPath(&data), api, &api, &resp.Diagnostics) + } if !ok { return } @@ -197,8 +214,11 @@ func (r *cms_action_deployResource) Update(ctx context.Context, req resource.Upd // Update from plan var api CMSActionDeployAPIModel - data.toAPI(&api) - if ok, _ := r.apiRequest(ctx, http.MethodPatch, r.apiPath(&data), api, &api, &resp.Diagnostics); !ok { + ok := data.toAPI(&api, &resp.Diagnostics) + if ok { + ok, _ = r.apiRequest(ctx, http.MethodPatch, r.apiPath(&data), api, &api, &resp.Diagnostics) + } + if !ok { return } diff --git a/kaleido/platform/cms_action_deploy_test.go b/kaleido/platform/cms_action_deploy_test.go index f9aa351..c800eb1 100644 --- a/kaleido/platform/cms_action_deploy_test.go +++ b/kaleido/platform/cms_action_deploy_test.go @@ -31,7 +31,11 @@ resource "kaleido_platform_cms_action_deploy" "cms_action_deploy1" { build = "build1" name = "deploy1" firefly_namespace = "ns1" - signing_key = "0xaabbccdd" + signing_key = "0xaabbccdd" + params_json = jsonencode([ + "param1", + "param2" + ]) } ` @@ -44,6 +48,10 @@ resource "kaleido_platform_cms_action_deploy" "cms_action_deploy1" { firefly_namespace = "ns1" signing_key = "0xaabbccdd" description = "deploy a thing" + params_json = jsonencode([ + "param1", + "param2" + ]) } ` @@ -111,7 +119,10 @@ func TestCMSActionDeploy1(t *testing.T) { "build": { "id": "build1" }, - "signingKey": "0xaabbccdd" + "signingKey": "0xaabbccdd", + "constructorParams": [ + "param1", "param2" + ] }, "output": { "status": "pending", diff --git a/kaleido/platform/common.go b/kaleido/platform/common.go index 5199a19..8143d94 100644 --- a/kaleido/platform/common.go +++ b/kaleido/platform/common.go @@ -238,6 +238,7 @@ func Resources() []func() resource.Resource { CMSActionDeployResourceFactory, CMSActionCreateAPIResourceFactory, AMSTaskResourceFactory, + AMSFFListenerResourceFactory, FireFlyRegistrationResourceFactory, } } diff --git a/kaleido/platform/mockserver_test.go b/kaleido/platform/mockserver_test.go index d6d68b1..ff56413 100644 --- a/kaleido/platform/mockserver_test.go +++ b/kaleido/platform/mockserver_test.go @@ -32,38 +32,40 @@ import ( ) type mockPlatform struct { - t *testing.T - lock sync.Mutex - router *mux.Router - server *httptest.Server - environments map[string]*EnvironmentAPIModel - runtimes map[string]*RuntimeAPIModel - services map[string]*ServiceAPIModel - networks map[string]*NetworkAPIModel - kmsWallets map[string]*KMSWalletAPIModel - kmsKeys map[string]*KMSKeyAPIModel - cmsBuilds map[string]*CMSBuildAPIModel - cmsActions map[string]CMSActionAPIBaseAccessor - amsTasks map[string]*AMSTaskAPIModel - ffsNode *FireFlyStatusNodeAPIModel - ffsOrg *FireFlyStatusOrgAPIModel - calls []string + t *testing.T + lock sync.Mutex + router *mux.Router + server *httptest.Server + environments map[string]*EnvironmentAPIModel + runtimes map[string]*RuntimeAPIModel + services map[string]*ServiceAPIModel + networks map[string]*NetworkAPIModel + kmsWallets map[string]*KMSWalletAPIModel + kmsKeys map[string]*KMSKeyAPIModel + cmsBuilds map[string]*CMSBuildAPIModel + cmsActions map[string]CMSActionAPIBaseAccessor + amsTasks map[string]*AMSTaskAPIModel + amsFFListeners map[string]*AMSFFListenerAPIModel + ffsNode *FireFlyStatusNodeAPIModel + ffsOrg *FireFlyStatusOrgAPIModel + calls []string } func startMockPlatformServer(t *testing.T) *mockPlatform { mp := &mockPlatform{ - t: t, - environments: make(map[string]*EnvironmentAPIModel), - runtimes: make(map[string]*RuntimeAPIModel), - services: make(map[string]*ServiceAPIModel), - networks: make(map[string]*NetworkAPIModel), - kmsWallets: make(map[string]*KMSWalletAPIModel), - kmsKeys: make(map[string]*KMSKeyAPIModel), - cmsBuilds: make(map[string]*CMSBuildAPIModel), - cmsActions: make(map[string]CMSActionAPIBaseAccessor), - amsTasks: make(map[string]*AMSTaskAPIModel), - router: mux.NewRouter(), - calls: []string{}, + t: t, + environments: make(map[string]*EnvironmentAPIModel), + runtimes: make(map[string]*RuntimeAPIModel), + services: make(map[string]*ServiceAPIModel), + networks: make(map[string]*NetworkAPIModel), + kmsWallets: make(map[string]*KMSWalletAPIModel), + kmsKeys: make(map[string]*KMSKeyAPIModel), + cmsBuilds: make(map[string]*CMSBuildAPIModel), + cmsActions: make(map[string]CMSActionAPIBaseAccessor), + amsTasks: make(map[string]*AMSTaskAPIModel), + amsFFListeners: make(map[string]*AMSFFListenerAPIModel), + router: mux.NewRouter(), + calls: []string{}, } // See environment_test.go mp.register("/api/v1/environments", http.MethodPost, mp.postEnvironment) @@ -118,6 +120,11 @@ func startMockPlatformServer(t *testing.T) *mockPlatform { mp.register("/endpoint/{env}/{service}/rest/api/v1/tasks/{task}", http.MethodPut, mp.putAMSTask) mp.register("/endpoint/{env}/{service}/rest/api/v1/tasks/{task}", http.MethodDelete, mp.deleteAMSTask) + // See ams_fflistener.go + mp.register("/endpoint/{env}/{service}/rest/api/v1/listeners/firefly/{listener}", http.MethodGet, mp.getAMSFFListener) + mp.register("/endpoint/{env}/{service}/rest/api/v1/listeners/firefly/{listener}", http.MethodPut, mp.putAMSFFListener) + mp.register("/endpoint/{env}/{service}/rest/api/v1/listeners/firefly/{listener}", http.MethodDelete, mp.deleteAMSFFListener) + // See firefly_registration.go mp.register("/endpoint/{env}/{service}/rest/api/v1/network/nodes/self", http.MethodPost, mp.postFireFlyRegistrationNode) mp.register("/endpoint/{env}/{service}/rest/api/v1/network/organizations/self", http.MethodPost, mp.postFireFlyRegistrationOrg)