Skip to content

Add create/delete commands for device/thing tags [IOT-1481] #53

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Nov 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ Once a device has been created thorugh the provisioning procedure, it can be del
Devices currently present on Arduino IoT Cloud can be retrieved by using this command:
`$ arduino-cloud-cli device list`

Add tags to a device. Tags should be passed as a comma-separated list of `<key>=<value>` items:

`$ arduino-cloud-cli device create-tags --id <deviceID> --tags <key0>=<value0>,<key1>=<value1>`

Delete specific tags of a device. The keys of the tags to delete should be passed in a comma-separated list of strings:

`$ arduino-cloud-cli device delete-tags --id <deviceID> --keys <key0>,<key1>`

## Thing commands

Things can be created starting from a template or by cloning another thing.
Expand Down Expand Up @@ -110,6 +118,15 @@ Bind a thing to an existing device:

`$ arduino-cloud-cli thing bind --id <thingID> --device-id <deviceID>`

Add tags to a thing. Tags should be passed as a comma-separated list of `<key>=<value>` items:

`$ arduino-cloud-cli thing create-tags --id <thingID> --tags <key0>=<value0>,<key1>=<value1>`

Delete specific tags of a thing. The keys of the tags to delete should be passed in a comma-separated list of strings:

`$ arduino-cloud-cli thing delete-tags --id <thingID> --keys <key0>,<key1>`


## Ota commands

Perform an OTA firmware update. Note that the binary file (`.bin`) should be compiled using an arduino core that supports the specified device.
Expand Down
3 changes: 3 additions & 0 deletions cli/device/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package device

import (
"github.com/arduino/arduino-cloud-cli/cli/device/tag"
"github.com/spf13/cobra"
)

Expand All @@ -31,6 +32,8 @@ func NewCommand() *cobra.Command {
deviceCommand.AddCommand(initCreateCommand())
deviceCommand.AddCommand(initListCommand())
deviceCommand.AddCommand(initDeleteCommand())
deviceCommand.AddCommand(tag.InitCreateTagsCommand())
deviceCommand.AddCommand(tag.InitDeleteTagsCommand())

return deviceCommand
}
70 changes: 70 additions & 0 deletions cli/device/tag/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// This file is part of arduino-cloud-cli.
//
// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

package tag

import (
"os"

"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cloud-cli/command/tag"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

var createTagsFlags struct {
id string
tags map[string]string
}

func InitCreateTagsCommand() *cobra.Command {
createTagsCommand := &cobra.Command{
Use: "create-tags",
Short: "Create or overwrite tags on a device",
Long: "Create or overwrite tags on a device of Arduino IoT Cloud",
Run: runCreateTagsCommand,
}
createTagsCommand.Flags().StringVarP(&createTagsFlags.id, "id", "i", "", "Device ID")
createTagsCommand.Flags().StringToStringVar(
&createTagsFlags.tags,
"tags",
nil,
"Comma-separated list of tags with format <key>=<value>.",
)
createTagsCommand.MarkFlagRequired("id")
createTagsCommand.MarkFlagRequired("tags")
return createTagsCommand
}

func runCreateTagsCommand(cmd *cobra.Command, args []string) {
logrus.Infof("Creating tags on device %s\n", createTagsFlags.id)

params := &tag.CreateTagsParams{
ID: createTagsFlags.id,
Tags: createTagsFlags.tags,
Resource: tag.Device,
}

err := tag.CreateTags(params)
if err != nil {
feedback.Errorf("Error during device create-tags: %v", err)
os.Exit(errorcodes.ErrGeneric)
}

logrus.Info("Tags successfully created")
}
67 changes: 67 additions & 0 deletions cli/device/tag/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// This file is part of arduino-cloud-cli.
//
// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

package tag

import (
"os"

"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cloud-cli/command/tag"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

var deleteTagsFlags struct {
id string
keys []string
}

func InitDeleteTagsCommand() *cobra.Command {
deleteTagsCommand := &cobra.Command{
Use: "delete-tags",
Short: "Delete tags of a device",
Long: "Delete tags of a device of Arduino IoT Cloud",
Run: runDeleteTagsCommand,
}

deleteTagsCommand.Flags().StringVarP(&deleteTagsFlags.id, "id", "i", "", "Device ID")
deleteTagsCommand.Flags().StringSliceVarP(&deleteTagsFlags.keys, "keys", "k", nil, "Comma-separated list of keys of tags to delete")

deleteTagsCommand.MarkFlagRequired("id")
deleteTagsCommand.MarkFlagRequired("keys")
return deleteTagsCommand
}

func runDeleteTagsCommand(cmd *cobra.Command, args []string) {
logrus.Infof("Deleting tags with keys %s\n", deleteTagsFlags.keys)

params := &tag.DeleteTagsParams{
ID: deleteTagsFlags.id,
Keys: deleteTagsFlags.keys,
Resource: tag.Device,
}

err := tag.DeleteTags(params)
if err != nil {
feedback.Errorf("Error during device delete-tags: %v", err)
os.Exit(errorcodes.ErrGeneric)
}

logrus.Info("Tags successfully deleted")
}
70 changes: 70 additions & 0 deletions cli/thing/tag/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// This file is part of arduino-cloud-cli.
//
// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

package tag

import (
"os"

"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cloud-cli/command/tag"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

var createTagsFlags struct {
id string
tags map[string]string
}

func InitCreateTagsCommand() *cobra.Command {
createTagsCommand := &cobra.Command{
Use: "create-tags",
Short: "Create or overwrite tags on a thing",
Long: "Create or overwrite tags on a thing of Arduino IoT Cloud",
Run: runCreateTagsCommand,
}
createTagsCommand.Flags().StringVarP(&createTagsFlags.id, "id", "i", "", "Thing ID")
createTagsCommand.Flags().StringToStringVar(
&createTagsFlags.tags,
"tags",
nil,
"Comma-separated list of tags with format <key>=<value>.",
)
createTagsCommand.MarkFlagRequired("id")
createTagsCommand.MarkFlagRequired("tags")
return createTagsCommand
}

func runCreateTagsCommand(cmd *cobra.Command, args []string) {
logrus.Infof("Creating tags on thing %s\n", createTagsFlags.id)

params := &tag.CreateTagsParams{
ID: createTagsFlags.id,
Tags: createTagsFlags.tags,
Resource: tag.Thing,
}

err := tag.CreateTags(params)
if err != nil {
feedback.Errorf("Error during thing create-tags: %v", err)
os.Exit(errorcodes.ErrGeneric)
}

logrus.Info("Tags successfully created")
}
67 changes: 67 additions & 0 deletions cli/thing/tag/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// This file is part of arduino-cloud-cli.
//
// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

package tag

import (
"os"

"github.com/arduino/arduino-cli/cli/errorcodes"
"github.com/arduino/arduino-cli/cli/feedback"
"github.com/arduino/arduino-cloud-cli/command/tag"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)

var deleteTagsFlags struct {
id string
keys []string
}

func InitDeleteTagsCommand() *cobra.Command {
deleteTagsCommand := &cobra.Command{
Use: "delete-tags",
Short: "Delete tags of a thing",
Long: "Delete tags of a thing of Arduino IoT Cloud",
Run: runDeleteTagsCommand,
}

deleteTagsCommand.Flags().StringVarP(&deleteTagsFlags.id, "id", "i", "", "Thing ID")
deleteTagsCommand.Flags().StringSliceVarP(&deleteTagsFlags.keys, "keys", "k", nil, "Comma-separated list of keys of tags to delete")

deleteTagsCommand.MarkFlagRequired("id")
deleteTagsCommand.MarkFlagRequired("keys")
return deleteTagsCommand
}

func runDeleteTagsCommand(cmd *cobra.Command, args []string) {
logrus.Infof("Deleting tags with keys %s\n", deleteTagsFlags.keys)

params := &tag.DeleteTagsParams{
ID: deleteTagsFlags.id,
Keys: deleteTagsFlags.keys,
Resource: tag.Thing,
}

err := tag.DeleteTags(params)
if err != nil {
feedback.Errorf("Error during thing delete-tags: %v", err)
os.Exit(errorcodes.ErrGeneric)
}

logrus.Info("Tags successfully deleted")
}
3 changes: 3 additions & 0 deletions cli/thing/thing.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package thing

import (
"github.com/arduino/arduino-cloud-cli/cli/thing/tag"
"github.com/spf13/cobra"
)

Expand All @@ -34,6 +35,8 @@ func NewCommand() *cobra.Command {
thingCommand.AddCommand(initDeleteCommand())
thingCommand.AddCommand(initExtractCommand())
thingCommand.AddCommand(initBindCommand())
thingCommand.AddCommand(tag.InitCreateTagsCommand())
thingCommand.AddCommand(tag.InitDeleteTagsCommand())

return thingCommand
}
56 changes: 56 additions & 0 deletions command/tag/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// This file is part of arduino-cloud-cli.
//
// Copyright (C) 2021 ARDUINO SA (http://www.arduino.cc/)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

package tag

import (
"errors"

"github.com/arduino/arduino-cloud-cli/internal/config"
"github.com/arduino/arduino-cloud-cli/internal/iot"
)

// CreateTagsParams contains the parameters needed to create or overwrite
// tags on a resource of Arduino IoT Cloud.
type CreateTagsParams struct {
ID string // Resource ID
Tags map[string]string // Map of tags to create
Resource ResourceType
}

// CreateTags allows to create or overwrite tags
// on a resource of Arduino IoT Cloud
func CreateTags(params *CreateTagsParams) error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could add a validation of params.Resource here so that if it doesn't have a valid value we avoid loading the configuration and instantiating the iot client for nothing.

What do you think?

conf, err := config.Retrieve()
if err != nil {
return err
}
iotClient, err := iot.NewClient(conf.Client, conf.Secret)
if err != nil {
return err
}

switch params.Resource {
case Thing:
err = iotClient.ThingTagsCreate(params.ID, params.Tags)
case Device:
err = iotClient.DeviceTagsCreate(params.ID, params.Tags)
default:
err = errors.New("passed Resource parameter is not valid")
}
return err
}
Loading