Пример #1
0
    def associate_devices(self, thing_names, config_file, region=None):
        # TODO remove this function when Group discovery is enriched
        """
        Using the `thing_names` values, associate existing Things in AWS IoT
        with the config of another Greengrass Group for use as Greengrass
        Devices.

        :param thing_names: the thing name or list of thing names to associate
            as Greengrass Devices
        :param config_file: config file used to track the Greengrass Devices in
            the group
        :param region: the region in which to associate devices.
            [default: us-west-2]
        """
        logging.info("associate_devices thing_names:{0}".format(thing_names))
        config = GroupConfigFile(config_file=config_file)
        if region is None:
            region = self._region
        devices = config['devices']
        if type(thing_names) is basestring:
            thing_names = [thing_names]
        iot_client = _get_iot_session(region=region)
        for thing_name in thing_names:
            thing = iot_client.describe_thing(thingName=thing_name)
            logging.info("Found existing Thing:{0}".format(thing))
            p = iot_client.list_thing_principals(thingName=thing_name)
            logging.info("Existing Thing has principals:{0}".format(p))
            devices[thing_name] = {
                'thing_arn': thing['attributes']['thingArn'],
                'cert_arn': p['principals'][0],
                'cert_id': thing['attributes']['certificateId'],
                'thing_name': thing_name
            }
            logging.info("Thing:'{0}' associated with config:'{1}'".format(
                thing_name, config_file))

        config['devices'] = devices
def core_connect(device_name, config_file, root_ca, certificate, private_key,
                 group_ca_path):
    global ggd_name, mqttc
    cfg = GroupConfigFile(config_file)
    ggd_name = cfg['devices'][device_name]['thing_name']
    iot_endpoint = cfg['misc']['iot_endpoint']

    dip = DiscoveryInfoProvider()
    dip.configureEndpoint(iot_endpoint)
    dip.configureCredentials(caPath=root_ca,
                             certPath=certificate,
                             keyPath=private_key)
    dip.configureTimeout(10)  # 10 sec
    logging.info("[button] Discovery using CA:{0} cert:{1} prv_key:{2}".format(
        root_ca, certificate, private_key))

    gg_core, discovery_info = utils.discover_configured_core(
        device_name=device_name,
        dip=dip,
        config_file=config_file,
    )
    if not gg_core:
        raise EnvironmentError("[button] Couldn't find the Core")

    ca_list = discovery_info.getAllCas()
    group_id, ca = ca_list[0]
    group_ca_file = utils.save_group_ca(ca, group_ca_path, group_id)

    mqttc = AWSIoTMQTTClient(ggd_name)
    # local Greengrass Core discovered, now connect to Core from this Device
    log.info("[button] gca_file:{0} cert:{1}".format(group_ca_file,
                                                     certificate))
    mqttc.configureCredentials(group_ca_file, private_key, certificate)
    mqttc.configureOfflinePublishQueueing(10, DROP_OLDEST)

    return mqttc, gg_core
Пример #3
0
                        help="Topic used to communicate arm telemetry.")
    parser.add_argument('--frequency',
                        default=1.0,
                        dest='frequency',
                        type=float,
                        help="Modify the default telemetry sample frequency.")
    parser.add_argument('--debug',
                        default=False,
                        action='store_true',
                        help="Activate debug output.")
    args = parser.parse_args()
    if args.debug:
        log.setLevel(logging.DEBUG)
        logging.getLogger('servode').setLevel(logging.DEBUG)

    cfg = GroupConfigFile(args.config_file)
    ggd_name = cfg['devices']['GGD_arm']['thing_name']
    ggd_ca_file_path = args.ca_file_path

    initialize()

    with ServoProtocol() as sp:
        sg = ServoGroup()
        sg['base'] = Servo(sp, ggd_config.arm_servo_ids[0], base_servo_cache)
        sg['femur01'] = Servo(sp, ggd_config.arm_servo_ids[1],
                              femur01_servo_cache)
        sg['femur02'] = Servo(sp, ggd_config.arm_servo_ids[2],
                              femur02_servo_cache)
        sg['tibia'] = Servo(sp, ggd_config.arm_servo_ids[3], tibia_servo_cache)
        sg['effector'] = Servo(sp, ggd_config.arm_servo_ids[4],
                               eff_servo_cache)
Пример #4
0
    def create_devices(self, thing_names, config_file, region=None,
                       cert_dir=None, append=False, account_id=None,
                       policy_name='ggd-discovery-policy', profile_name=None):
        """
        Using the `thing_names` values, creates Things in AWS IoT, attaches and
        downloads new keys & certs to the certificate directory, then records
        the created information in the local config file for inclusion in the
        Greengrass Group as Greengrass Devices.

        :param thing_names: the thing name or list of thing names to create and
            use as Greengrass Devices
        :param config_file: config file used to track the Greengrass Devices in
            the group
        :param region: the region in which to create the new devices.
            [default: us-west-2]
        :param cert_dir: the directory in which to store the thing's keys and
            certs. If `None` then use the current directory.
        :param append: append the created devices to the list of devices in the
            config file. [default: False]
        :param account_id: the account ID in which to create devices. If 'None'
            the config_file will be checked for an `account_id` value in the
            `misc` section.
        :param policy_name: the name of the policy to associate with the device.
            [default: 'ggd-discovery-policy']
        :param profile_name: the name of the `awscli` profile to use.
            [default: None]
        """
        logging.info("create_devices thing_names:{0}".format(thing_names))
        config = GroupConfigFile(config_file=config_file)
        if append is False and config.is_device_fresh() is False:
            raise ValueError(
                "Config file tracking previously created devices. Append "
                "devices instead"
            )

        if region is None:
            region = self._region
        if account_id is None:
            account_id = self._account_id
        devices = dict()
        if append:
            devices = config['devices']
        if type(thing_names) is str:
            thing_names = [thing_names]

        iot_client = _get_iot_session(region=region, profile_name=profile_name)
        for thing_name in thing_names:
            keys_cert, thing = self.create_thing(thing_name, region, cert_dir)
            cert_arn = keys_cert['certificateArn']
            devices[thing_name] = {
                'thing_arn': thing['thingArn'],
                'cert_arn': cert_arn,
                'cert_id': keys_cert['certificateId'],
                'thing_name': thing_name
            }
            logging.info("Thing:'{0}' associated with cert:'{1}'".format(
                thing_name, cert_arn))
            device_policy = self.get_device_policy(
                device_name=thing_name, account_id=account_id, region=region
            )
            self._create_attach_thing_policy(cert_arn, device_policy,
                                             iot_client, policy_name)

        config['devices'] = devices
        logging.info("create_devices cfg:{0}".format(config))
Пример #5
0
    def create(self, group_type, config_file, group_name=None,
               region=None, profile_name=None):
        """
        Create a Greengrass group in the given region.

        :param group_type: the type of group to create. Must match a `key` in
            the `group_types` dict
        :param config_file: config file of the group to create
        :param group_name: the name of the group. If no name is given, then
            group_type will be used.
        :param region: the region in which to create the new group.
            [default: us-west-2]
        :param profile_name: the name of the `awscli` profile to use.
            [default: None]
        """
        logging.info("[begin] create command using group_types:{0}".format(
            self.group_types))

        config = GroupConfigFile(config_file=config_file)
        if config.is_fresh() is False:
            raise ValueError(
                "Config file already tracking previously created group"
            )

        if group_type not in self.group_types.keys():
            raise ValueError("Can only create {0} groups.".format(
                self.group_types)
            )

        if region is None:
            region = self._region

        # create an instance of the requested group type that uses the given
        # config file and region
        gt = self.group_types[group_type](config=config, region=region)

        # get and store the account's IoT endpoint for future use
        ep = _get_iot_session(region=region).describe_endpoint()
        misc = config['misc']
        misc['iot_endpoint'] = ep['endpointAddress']
        config['misc'] = misc

        # Create a Group
        logging.info("[begin] Creating a Greengrass Group")
        if group_name is None:
            group_name = group_type

        gg_client = _get_gg_session(region=region, profile_name=profile_name)

        group_info = gg_client.create_group(Name="{0}".format(group_name))
        config['group'] = {"id": group_info['Id']}

        # setup the policies and roles
        gt.create_and_attach_thing_policy()
        gt.create_and_attach_iam_role()

        cl_arn = self._create_core_definition(
            gg_client=gg_client, group_type=gt,
            config=config, group_name=group_name
        )
        dl_arn = self._create_device_definition(
            gg_client=gg_client, group_type=gt,
            config=config, group_name=group_name
        )
        lv_arn = self._create_function_definition(
            gg_client=gg_client, group_type=gt,
            config=config
        )
        log_arn = self._create_logger_definition(
            gg_client=gg_client, group_type=gt,
            config=config
        )
        sub_arn = self._create_subscription_definition(
            gg_client=gg_client, group_type=gt,
            config=config
        )

        logging.info(
            'Group details, core_def:{0} device_def:{1} func_def:{2} '
            'logger_def:{3} subs_def:{4}'.format(
                cl_arn, dl_arn, lv_arn, log_arn, sub_arn)
        )

        # Add all the constituent parts to the Greengrass Group
        group_args = {'GroupId': group_info['Id']}
        if cl_arn:
            group_args['CoreDefinitionVersionArn'] = cl_arn
        if dl_arn:
            group_args['DeviceDefinitionVersionArn'] = dl_arn
        if lv_arn:
            group_args['FunctionDefinitionVersionArn'] = lv_arn
        if log_arn:
            group_args['LoggerDefinitionVersionArn'] = log_arn
        if sub_arn:
            group_args['SubscriptionDefinitionVersionArn'] = sub_arn
        grp = gg_client.create_group_version(
            **group_args
        )

        # store info about the provisioned artifacts into the local config file
        config['group'] = {
            "id": group_info['Id'],
            "version_arn": grp['Arn'],
            "version": grp['Version'],
            "name": group_name
        }
        logging.info(
            "[end] Created Greengrass Group {0}".format(group_info['Id']))
Пример #6
0
    def create_core(self,
                    thing_name,
                    config_file,
                    region=None,
                    cert_dir=None,
                    account_id=None,
                    policy_name='ggc-default-policy',
                    profile_name=None):
        """
        Using the `thing_name` value, creates a Thing in AWS IoT, attaches and
        downloads new keys & certs to the certificate directory, then records
        the created information in the local config file for inclusion in the
        Greengrass Group as a Greengrass Core.

        :param thing_name: the name of the thing to create and use as a
            Greengrass Core
        :param config_file: config file used to track the Greengrass Core in the
            group
        :param region: the region in which to create the new core.
            [default: us-west-2]
        :param cert_dir: the directory in which to store the thing's keys and
            certs. If `None` then use the current directory.
        :param account_id: the account_id in which to create the new core.
            [default: None]
        :param policy_name: the name of the policy to associate with the device.
            [default: 'ggc-default-policy']
        :param profile_name: the name of the `awscli` profile to use.
            [default: None]
        """
        config = GroupConfigFile(config_file=config_file)
        if config.is_fresh() is False:
            raise ValueError(
                "Config file already tracking previously created core or group"
            )
        if region is None:
            region = self._region
        if account_id is None:
            account_id = self._account_id
        keys_cert, thing = self.create_thing(thing_name, region, cert_dir)

        cert_arn = keys_cert['certificateArn']
        config['core'] = {
            'thing_arn': thing['thingArn'],
            'cert_arn': cert_arn,
            'cert_id': keys_cert['certificateId'],
            'thing_name': thing_name
        }
        logging.debug("create_core cfg:{0}".format(config))
        logging.info("Thing:'{0}' associated with cert:'{1}'".format(
            thing_name, cert_arn))
        core_policy = self.get_core_policy(core_name=thing_name,
                                           account_id=account_id,
                                           region=region)
        iot_client = _get_iot_session(region=region, profile_name=profile_name)
        self._create_attach_thing_policy(cert_arn,
                                         core_policy,
                                         iot_client=iot_client,
                                         policy_name=policy_name)
        misc = config['misc']
        misc['policy_name'] = policy_name
        config['misc'] = misc
def initialize(device_name, config_file, root_ca, certificate, private_key,
               group_ca_path):
    # read the config file
    cfg = GroupConfigFile(config_file)

    ggd_name = cfg['devices'][device_name]['thing_name']
    iot_endpoint = cfg['misc']['iot_endpoint']
    # prep for discovery
    dip = DiscoveryInfoProvider()
    dip.configureEndpoint(iot_endpoint)
    dip.configureCredentials(caPath=pa.root_ca,
                             certPath=pa.certificate,
                             keyPath=pa.private_key)
    dip.configureTimeout(10)  # 10 sec
    logging.info("Discovery using CA:{0} cert:{1} prv_key:{2}".format(
        pa.root_ca, pa.certificate, pa.private_key))
    discovered, discovery_info = utils.ggc_discovery(
        thing_name=ggd_name, discovery_info_provider=dip, max_groups=3)

    local, remote = _find_cores(cfg, discovery_info, iot_endpoint)
    # Save each group's CAs to use as a CA file later
    local_core_ca_file = utils.save_group_ca(local['ca'][0], group_ca_path,
                                             local['core'].groupId)
    for r in remote:
        remote[r]['ca_file'] = utils.save_group_ca(remote[r]['ca'][0],
                                                   group_ca_path,
                                                   remote[r]['core'].groupId)

    # create and connect MQTT client pointed toward the Master Greengrass Core
    mqttc_m = AWSIoTMQTTClient(ggd_name)
    log.info("[initialize] local gca_file:{0} cert:{1}".format(
        local_core_ca_file, certificate))
    mqttc_m.configureCredentials(local_core_ca_file, private_key, certificate)
    mqttc_m.configureOfflinePublishQueueing(10, DROP_OLDEST)

    log.info("[initialize] Starting connection to Master Core")
    if utils.mqtt_connect(mqtt_client=mqttc_m, core_info=local['core']):
        log.info("[initialize] Connected to Master Core")
    else:
        log.error("[initialize] could not connect to Master Core")

    # create and connect MQTT clients pointed toward the remote Greengrass Cores
    mqttc_list = list()
    for r in remote:
        remote_mqttc = AWSIoTMQTTClient(ggd_name)
        log.info("[initialize] local gca_file:{0} cert:{1}".format(
            r, certificate))
        remote_mqttc.configureCredentials(remote[r]['ca_file'], private_key,
                                          certificate)
        remote_mqttc.configureOfflinePublishQueueing(10, DROP_OLDEST)
        log.info("[initialize] Starting connection to Remote Core")
        if utils.mqtt_connect(mqtt_client=remote_mqttc,
                              core_info=remote[r]['core']):
            log.info("[initialize] Connected to Remote Core:{0}".format(
                remote[r]['core'].coreThingArn))
            mqttc_list.append(remote_mqttc)
        else:
            log.error(
                "[initialize] could not connect to Remote Core:{0}".format(
                    remote[r]['core'].coreThingArn))

    return mqttc_m, mqttc_list
Пример #8
0
    def create(self, group_type, config_file,
               group_name=None, region='us-west-2'):
        """
        Create a Greengrass group in the given region.

        :param group_type: the type of group to create. Must match a `key` in
            the `group_types` dict
        :param config_file: config file of the group to create
        :param group_name: the name of the group. If no name is given, then
            group_type will be used.
        :param region: the region in which to create the new group. [default: us-west-2]
        """
        logging.info("[begin] create command using group_types:{0}".format(
            self.group_types))

        config = GroupConfigFile(config_file=config_file)
        if config.is_fresh() is False:
            raise ValueError(
                "Config file already tracking previously created group"
            )

        if group_type not in self.group_types.keys():
            raise ValueError("Can only create {0} groups.".format(
                self.group_types)
            )

        # create an instance of the requested group type that uses the given
        # config file and region
        gt = self.group_types[group_type](config=config, region=region)

        # Create a Group
        logging.info("[begin] Creating a Greengrass Group")
        if group_name is None:
            group_name = group_type

        gg_client = boto3.client("greengrass", region_name=region)

        group_info = gg_client.create_group(Name="{0}_group".format(group_name))
        config['group'] = {"id": group_info['Id']}

        # setup the policies and roles
        gt.create_and_attach_thing_policy()
        gt.create_and_attach_iam_role()

        cl_arn = self._create_core_definition(
            gg_client=gg_client, group_type=gt,
            config=config, group_name=group_name
        )
        dl_arn = self._create_device_definition(
            gg_client=gg_client, group_type=gt,
            config=config, group_name=group_name
        )
        lv_arn = self._create_function_definition(
            gg_client=gg_client, group_type=gt, config=config
        )
        log_arn = self._create_logger_definition(
            gg_client=gg_client, group_type=gt, config=config
        )
        sub_arn = self._create_subscription_definition(
            gg_client=gg_client, group_type=gt, config=config
        )

        # Add all the constituent parts to the Greengrass Group
        grp = gg_client.create_group_version(
            GroupId=group_info['Id'],
            CoreDefinitionVersionArn=cl_arn,
            DeviceDefinitionVersionArn=dl_arn,
            FunctionDefinitionVersionArn=lv_arn,
            LoggerDefinitionVersionArn=log_arn,
            SubscriptionDefinitionVersionArn=sub_arn
        )
        # store info about the provisioned artifacts into the local config file
        config['group'] = {
            "id": group_info['Id'],
            "version_arn": grp['Arn'],
            "version": grp['Version']
        }
        logging.info(
            "[end] Created Greengrass Group {0}".format(group_info['Id']))
Пример #9
0
def initialize(device_name, config_file, root_ca, certificate, private_key,
               group_ca_path):
    global ggd_name

    cfg = GroupConfigFile(config_file)
    local = dict()
    remote = dict()

    # determine heartbeat device's thing name and endpoint for MQTT clients
    ggd_name = cfg['devices'][device_name]['thing_name']
    iot_endpoint = cfg['misc']['iot_endpoint']

    # Discover Greengrass Core
    dip = DiscoveryInfoProvider()
    dip.configureEndpoint(iot_endpoint)
    dip.configureCredentials(
        caPath=root_ca, certPath=certificate, keyPath=private_key
    )
    dip.configureTimeout(10)  # 10 sec
    log.info("Discovery using CA: {0} certificate: {1} prv_key: {2}".format(
        root_ca, certificate, private_key
    ))
    # Now discover the groups in which this device is a member.
    # The arm should only be in two groups. The local and master groups.
    discovered, discovery_info = utils.ggc_discovery(
        ggd_name, dip, retry_count=10, max_groups=2
    )

    # Each group returned has a groupId which can compare to the configured
    # groupId in the config file. If the IDs match, the 'local' Group has been
    # found and therefore local core.
    # If the groupId's do not match, the 'remote' or 'master' group has been
    # found.
    group_list = discovery_info.getAllGroups()
    for g in group_list:
        logging.info("[initialize] group_id:{0}".format(g.groupId))
        if g.groupId == cfg['group']['id']:
            local_cores = g.coreConnectivityInfoList
            local['core'] = local_cores[0]  # just grab first core as local
            local['ca'] = g.caList
        else:
            remote_cores = g.coreConnectivityInfoList
            remote['core'] = remote_cores[0]  # just grab first core as remote
            remote['ca'] = g.caList

    if len(local) > 1 and len(remote) > 1:
        logging.info("[initialize] local_core:{0} remote_core:{1}".format(
            local, remote
        ))
    else:
        raise EnvironmentError("Couldn't find the arm's Cores.")

    # just save one of the group's CAs to use as a CA file later
    local_core_ca_file = utils.save_group_ca(
        local['ca'][0], group_ca_path, local['core'].groupId
    )
    remote_core_ca_file = utils.save_group_ca(
        remote['ca'][0], group_ca_path, remote['core'].groupId
    )

    # Greengrass Cores discovered, now connect to Cores from this Device
    # get a client to send telemetry
    local_mqttc = AWSIoTMQTTClient(ggd_name)
    log.info("[initialize] local gca_file:{0} cert:{1}".format(
        local_core_ca_file, certificate))
    local_mqttc.configureCredentials(
        local_core_ca_file, private_key, certificate
    )
    local_mqttc.configureOfflinePublishQueueing(10, DROP_OLDEST)

    if not utils.mqtt_connect(mqtt_client=local_mqttc, core_info=local['core']):
        raise EnvironmentError("Connection to GG Core MQTT failed.")

    # get a shadow client to receive commands
    master_shadow_client = AWSIoTMQTTShadowClient(ggd_name)
    log.info("[initialize] remote ca_file:{0} cert:{1}".format(
        local_core_ca_file, certificate))
    remote_mqttc = master_shadow_client.getMQTTConnection()
    remote_mqttc.configureCredentials(
        remote_core_ca_file, private_key, certificate
    )

    if not utils.mqtt_connect(mqtt_client=master_shadow_client,
                              core_info=remote['core']):
        raise EnvironmentError("Connection to Master Shadow failed.")

    # create and register the shadow handler on delta topics for commands
    # with a persistent connection to the Master shadow
    master_shadow = master_shadow_client.createShadowHandlerWithName(
        cfg['misc']['master_shadow_name'], True)
    log.info("[initialize] created handler for shadow name: {0}".format(
        cfg['misc']['master_shadow_name']
    ))
    token = master_shadow.shadowGet(shadow_mgr, 5)
    log.info("[initialize] shadowGet() tk:{0}".format(token))

    return local_mqttc, remote_mqttc, master_shadow