From e2b4157ce06dea1a7221774fac1ea4c9c81c9643 Mon Sep 17 00:00:00 2001 From: reubenmiller Date: Sun, 1 Dec 2024 10:36:22 +0100 Subject: [PATCH] feat(software install): add softwareType field by looking up the software --- api/spec/json/softwareVersions.json | 9 +++- api/spec/yaml/softwareVersions.yaml | 7 ++- pkg/c8yfetcher/c8yfetcher.go | 25 ++++++++++- .../software/versions/install/install.auto.go | 6 ++- pkg/cmdparser/cmdparser.go | 2 +- .../New-C8yApiGoGetValueFromFlag.ps1 | 2 +- .../install/software_versions_install.yaml | 43 ++++++++++++++++--- tests/scripts/setup.sh | 7 ++- .../PSc8y/Public/Install-SoftwareVersion.ps1 | 7 ++- 9 files changed, 93 insertions(+), 15 deletions(-) diff --git a/api/spec/json/softwareVersions.json b/api/spec/json/softwareVersions.json index c3777dda1..85a995cdc 100644 --- a/api/spec/json/softwareVersions.json +++ b/api/spec/json/softwareVersions.json @@ -382,7 +382,14 @@ "type": "string", "required": false, "property": "c8y_SoftwareUpdate.0.url", - "description": "Software url. Leave blank to automatically set it if a matching firmware/version is found in the c8y firmware repository" + "description": "Software url. Leave blank to automatically set it if a matching software/version is found in the c8y software repository" + }, + { + "name": "softwareType", + "type": "string", + "required": false, + "property": "c8y_SoftwareUpdate.0.softwareType", + "description": "Software type. Leave blank to automatically set it if a matching software/version is found in the c8y software repository" }, { "name": "description", diff --git a/api/spec/yaml/softwareVersions.yaml b/api/spec/yaml/softwareVersions.yaml index 93837bdec..c033ccc3a 100644 --- a/api/spec/yaml/softwareVersions.yaml +++ b/api/spec/yaml/softwareVersions.yaml @@ -294,8 +294,13 @@ commands: type: 'string' required: false property: c8y_SoftwareUpdate.0.url - description: Software url. Leave blank to automatically set it if a matching firmware/version is found in the c8y firmware repository + description: Software url. Leave blank to automatically set it if a matching software/version is found in the c8y software repository + - name: softwareType + type: string + required: false + property: c8y_SoftwareUpdate.0.softwareType + description: Software type. Leave blank to automatically set it if a matching software/version is found in the c8y software repository - name: description type: string diff --git a/pkg/c8yfetcher/c8yfetcher.go b/pkg/c8yfetcher/c8yfetcher.go index d7d5ca8fe..c7968c397 100644 --- a/pkg/c8yfetcher/c8yfetcher.go +++ b/pkg/c8yfetcher/c8yfetcher.go @@ -710,7 +710,7 @@ func WithSoftwareByNameFirstMatch(factory *cmdutil.Factory, args []string, opts } // WithSoftwareVersionData adds software information (name, version and url) -func WithSoftwareVersionData(factory *cmdutil.Factory, flagSoftware, flagVersion, flagURL string, args []string, opts ...string) flags.GetOption { +func WithSoftwareVersionData(factory *cmdutil.Factory, flagSoftware, flagVersion, flagURL string, flagSoftwareType string, args []string, opts ...string) flags.GetOption { return func(cmd *cobra.Command, inputIterators *flags.RequestInputIterators) (string, interface{}, error) { client, err := factory.Client() if err != nil { @@ -731,10 +731,33 @@ func WithSoftwareVersionData(factory *cmdutil.Factory, flagSoftware, flagVersion url = v[0] } + softwareType := "" + if v, err := flags.GetFlagStringValues(cmd, flagSoftwareType); err == nil && len(v) > 0 { + softwareType = v[0] + } + + if softwareType == "" && software != "" { + // Set software type by looking up the software (if found) + matchingSoftware, _, err := client.Software.GetSoftwareByName(c8y.WithDisabledDryRunContext(context.Background()), software, c8y.NewPaginationOptions(5)) + if err != nil { + return "", "", err + } + + if len(matchingSoftware.ManagedObjects) > 0 { + if v := matchingSoftware.Items[0].Get("softwareType"); v.Exists() { + softwareType = v.String() + } + } + } + _, dst, _ := flags.UnpackGetterOptions("", opts...) output := map[string]string{} + if softwareType != "" { + output["softwareType"] = softwareType + } + // If version is empty, then pass the values as is if version == "" || (software != "" && version != "" && url != "") { output["name"] = software diff --git a/pkg/cmd/software/versions/install/install.auto.go b/pkg/cmd/software/versions/install/install.auto.go index 18ba11c15..6a24a7882 100644 --- a/pkg/cmd/software/versions/install/install.auto.go +++ b/pkg/cmd/software/versions/install/install.auto.go @@ -54,7 +54,8 @@ Install a software package version with an explicit url cmd.Flags().StringSlice("device", []string{""}, "Device or agent where the software should be installed (accepts pipeline)") cmd.Flags().String("software", "", "Software name (required)") cmd.Flags().String("version", "", "Software version id or name") - cmd.Flags().String("url", "", "Software url. Leave blank to automatically set it if a matching firmware/version is found in the c8y firmware repository") + cmd.Flags().String("url", "", "Software url. Leave blank to automatically set it if a matching software/version is found in the c8y software repository") + cmd.Flags().String("softwareType", "", "Software type. Leave blank to automatically set it if a matching software/version is found in the c8y software repository") cmd.Flags().String("description", "Install software package", "Operation description") cmd.Flags().String("action", "install", "Software action") @@ -156,8 +157,9 @@ func (n *InstallCmd) RunE(cmd *cobra.Command, args []string) error { flags.WithStringValue("software", "c8y_SoftwareUpdate.0.name"), flags.WithStringValue("version", "c8y_SoftwareUpdate.0.version"), flags.WithStringValue("url", "c8y_SoftwareUpdate.0.url"), + flags.WithStringValue("softwareType", "c8y_SoftwareUpdate.0.softwareType"), flags.WithStringValue("description", "description"), - c8yfetcher.WithSoftwareVersionData(n.factory, "software", "version", "url", args, "", "c8y_SoftwareUpdate.0"), + c8yfetcher.WithSoftwareVersionData(n.factory, "software", "version", "url", "softwareType", args, "", "c8y_SoftwareUpdate.0"), flags.WithStringValue("action", "c8y_SoftwareUpdate.0.action"), cmdutil.WithTemplateValue(n.factory), flags.WithTemplateVariablesValue(), diff --git a/pkg/cmdparser/cmdparser.go b/pkg/cmdparser/cmdparser.go index 51e9c8626..49255fff3 100644 --- a/pkg/cmdparser/cmdparser.go +++ b/pkg/cmdparser/cmdparser.go @@ -451,7 +451,7 @@ func GetOption(cmd *CmdOptions, p *models.Parameter, factory *cmdutil.Factory, a opts = append(opts, c8yfetcher.WithSoftwareByNameFirstMatch(factory, args, p.Name, targetProp, p.Format)) case "softwareDetails": - opts = append(opts, c8yfetcher.WithSoftwareVersionData(factory, p.GetDependentProperty(0, "software"), p.Name, p.GetDependentProperty(1, "url"), args, "", targetProp, p.Format)) + opts = append(opts, c8yfetcher.WithSoftwareVersionData(factory, p.GetDependentProperty(0, "software"), p.Name, p.GetDependentProperty(1, "url"), p.GetDependentProperty(2, "softwareType"), args, "", targetProp, p.Format)) case "configurationDetails": opts = append(opts, c8yfetcher.WithConfigurationFileData(factory, p.Name, p.GetDependentProperty(0, "configurationType"), p.GetDependentProperty(1, "url"), args, "", targetProp, p.Format)) diff --git a/scripts/build-cli/New-C8yApiGoGetValueFromFlag.ps1 b/scripts/build-cli/New-C8yApiGoGetValueFromFlag.ps1 index 8dd62ed6d..7cf5e2195 100644 --- a/scripts/build-cli/New-C8yApiGoGetValueFromFlag.ps1 +++ b/scripts/build-cli/New-C8yApiGoGetValueFromFlag.ps1 @@ -140,7 +140,7 @@ "software[]" = "c8yfetcher.WithSoftwareByNameFirstMatch(n.factory, args, `"${prop}`", `"${queryParam}`"$FormatValue)," "softwareDetails" = @( - "c8yfetcher.WithSoftwareVersionData(n.factory, `"software`", `"version`", `"url`", args, `"`", `"${queryParam}`"$FormatValue)," + "c8yfetcher.WithSoftwareVersionData(n.factory, `"software`", `"version`", `"url`", `"softwareType`", args, `"`", `"${queryParam}`"$FormatValue)," ) -join "`n" "configurationDetails" = @( diff --git a/tests/manual/software/install/software_versions_install.yaml b/tests/manual/software/install/software_versions_install.yaml index 0466d66c5..0d1c89605 100644 --- a/tests/manual/software/install/software_versions_install.yaml +++ b/tests/manual/software/install/software_versions_install.yaml @@ -10,7 +10,7 @@ config: tests: It creates an operation to update software without a version: command: | - c8y software versions install --device 1 --software "myapp" --description "Installing software" | + c8y software versions install --device 1 --software "userapp1" --description "Installing software" | c8y util show --select method,pathEncoded,body --compact=false exit-code: 0 stdout: @@ -20,7 +20,7 @@ tests: "c8y_SoftwareUpdate": [ { "action": "install", - "name": "myapp", + "name": "userapp1", "url": "", "version": "" } @@ -36,7 +36,7 @@ tests: command: | c8y software versions install \ --device 1 \ - --software "myapp" \ + --software "userapp1" \ --description "Installing software" \ --url "https://test.com/binary/package.zip" | c8y util show --select method,pathEncoded,body --compact=false @@ -48,7 +48,7 @@ tests: "c8y_SoftwareUpdate": [ { "action": "install", - "name": "myapp", + "name": "userapp1", "url": "https://test.com/binary/package.zip", "version": "" } @@ -77,6 +77,7 @@ tests: { "action": "install", "name": "my-app", + "softwareType": "linux-package", "url": "https://example.com/debian/my-app-1.2.3.deb", "version": "1.2.3" } @@ -106,6 +107,7 @@ tests: { "action": "install", "name": "my-app", + "softwareType": "linux-package", "url": "https://test.com/binary/package.zip", "version": "1.2.3" } @@ -115,4 +117,35 @@ tests: }, "method": "POST", "pathEncoded": "/devicecontrol/operations" - } \ No newline at end of file + } + + It creates an operation to update software with a version but a custom softwareType: + command: | + c8y software versions install \ + --device 1 \ + --software "my-app" \ + --version "1.2.3" \ + --softwareType otherType \ + --description "Installing software" \ + --url "https://test.com/binary/package.zip" | + c8y util show --select method,pathEncoded,body --compact=false + exit-code: 0 + stdout: + exactly: | + { + "body": { + "c8y_SoftwareUpdate": [ + { + "action": "install", + "name": "my-app", + "softwareType": "otherType", + "url": "https://test.com/binary/package.zip", + "version": "1.2.3" + } + ], + "description": "Installing software", + "deviceId": "1" + }, + "method": "POST", + "pathEncoded": "/devicecontrol/operations" + } diff --git a/tests/scripts/setup.sh b/tests/scripts/setup.sh index 8bdbc22be..72d6197ae 100755 --- a/tests/scripts/setup.sh +++ b/tests/scripts/setup.sh @@ -44,7 +44,7 @@ setup () { create_firmware_version "iot-linux" "1.0.0" "https://example.com" create_firmware_patch_version "iot-linux" "1.0.1" "https://example.com/patch1" - create_software "my-app" + create_software "my-app" "linux-package" create_software_version "my-app" "1.2.3" "https://example.com/debian/my-app-1.2.3.deb" create_device_profile "profile01" @@ -203,8 +203,11 @@ create_configuration () { create_software () { local name="$1" - c8y software get -n --id "$name" --silentStatusCodes 404 || + local software_type="$2" + { + c8y software get -n --id "$name" --silentStatusCodes 404 || c8y software create -n --name "$name" + } | c8y software update --softwareType "$software_type" } create_software_version () { diff --git a/tools/PSc8y/Public/Install-SoftwareVersion.ps1 b/tools/PSc8y/Public/Install-SoftwareVersion.ps1 index 532fd0459..f1e7b3a82 100644 --- a/tools/PSc8y/Public/Install-SoftwareVersion.ps1 +++ b/tools/PSc8y/Public/Install-SoftwareVersion.ps1 @@ -38,11 +38,16 @@ Get a software package [object[]] $Version, - # Software url. Leave blank to automatically set it if a matching firmware/version is found in the c8y firmware repository + # Software url. Leave blank to automatically set it if a matching software/version is found in the c8y software repository [Parameter()] [string] $Url, + # Software type. Leave blank to automatically set it if a matching software/version is found in the c8y software repository + [Parameter()] + [string] + $SoftwareType, + # Operation description [Parameter()] [string]