• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mendersoftware / mender-auth-azure-iot / 5314301078

17 Nov 2021 07:12PM UTC coverage: 34.239%. Remained the same
5314301078

push

coveralls-python

web-flow
Merge pull request #7 from oleorhagen/MEN-5141-bak

MEN-5141: Implement the Device Twin sync with IoT Hub

181 of 181 new or added lines in 5 files covered. (100.0%)

63 of 184 relevant lines covered (34.24%)

0.34 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/daemon/daemon.py
1
# Copyright 2021 Northern.tech AS
2
#
3
#    Licensed under the Apache License, Version 2.0 (the "License");
4
#    you may not use this file except in compliance with the License.
5
#    You may obtain a copy of the License at
6
#
7
#        http://www.apache.org/licenses/LICENSE-2.0
8
#
9
#    Unless required by applicable law or agreed to in writing, software
10
#    distributed under the License is distributed on an "AS IS" BASIS,
11
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
#    See the License for the specific language governing permissions and
13
#    limitations under the License.
14
import argparse
×
15
import logging
×
16
import sys
×
17
import time
×
18
from logging.handlers import SysLogHandler
×
19

20
from azure.iot.device import IoTHubDeviceClient  # type: ignore
×
21

22
from daemon._version import __version__ as package_version
×
23
from daemon.config import config
×
24
from daemon.config.config import NoConfigurationFileError
×
25
from daemon.scripts import identity
×
26
from daemon.settings.settings import PATHS as Config
×
27

28
log = logging.getLogger()
×
29

30
DEVICE_UPDATE_INTERVAL = 60 * 60
×
31

32

33
def send_message(device_client, reported_properties):
×
34
    device_client.patch_twin_reported_properties(reported_properties)
×
35

36

37
def get_message(device_client):
×
38
    twin = device_client.get_twin()
×
39
    log.info("Twin document:")
×
40
    log.info(f"{twin}")
×
41
    return twin
×
42

43

44
def run_version(_):
×
45
    print(f"version: {package_version}")
×
46

47

48
def run_daemon(args):
×
49
    jwt_token = ""
×
50
    try:
×
51
        connection_string = config.load(Config.conf_file).ConnectionString
×
52
    except NoConfigurationFileError as e:
×
53
        log.error(e)
×
54
        return 1
×
55
    if Config.server_cert != "":
×
56
        server_cert = Config.server_cert
×
57
        try:
×
58
            certfile = open(server_cert)
×
59
        except FileNotFoundError as e:
×
60
            log.error(e)
×
61
            return 1
×
62
        server_cert_raw = certfile.read()
×
63
        device_client = IoTHubDeviceClient.create_from_connection_string(
×
64
            connection_string, server_verification_cert=server_cert_raw
65
        )
66
    else:
67
        device_client = IoTHubDeviceClient.create_from_connection_string(
×
68
            connection_string, server_verification_cert=""
69
        )
70
    try:
×
71
        open(Config.identity_scripts)
×
72
    except FileNotFoundError as e:
×
73
        log.error(e)
×
74
        return 1
×
75
    device_identity = identity.aggregate(Config.identity_scripts)
×
76
    log.info(f"Device ID: {device_identity}")
×
77
    device_client.connect()
×
78
    log.info("Connected to the IoT Hub")
×
79
    while True:
80
        log.info("Getting twin...")
×
81
        twin = get_message(device_client)
×
82
        desired = twin.get("desired", None)
×
83
        if not desired:
×
84
            log.error("desired data not present in the response")
×
85
            return 1
×
86
        log.info("Sending twin report...")
×
87
        if jwt_token != desired.get("JWT", ""):
×
88
            log.info(
×
89
                "The JWT Token, or the device identity has changed in the desired vs reported state"
90
            )
91
            log.info("Resending")
×
92
            jwt_token = desired.get("JWT", "")
×
93
            send_message(
×
94
                device_client,
95
                reported_properties={"device_id": device_identity, "JWT": jwt_token,},
96
            )
97
        if args.stop:
×
98
            return 1
×
99
        log.info(f"Going to sleep for {DEVICE_UPDATE_INTERVAL} seconds...")
×
100
        time.sleep(DEVICE_UPDATE_INTERVAL)
×
101

102

103
def setup_logging(args):
×
104
    handlers = []
×
105
    stream_handler = logging.StreamHandler()
×
106
    stream_handler.setFormatter(
×
107
        logging.Formatter(
108
            datefmt="%Y-%m-%d %H:%M:%S",
109
            fmt="%(name)s %(asctime)s %(levelname)-8s %(message)s",
110
        )
111
    )
112
    handlers.append(stream_handler)
×
113
    level = {
×
114
        "debug": logging.DEBUG,
115
        "info": logging.INFO,
116
        "warning": logging.WARNING,
117
        "error": logging.ERROR,
118
        "critical": logging.CRITICAL,
119
    }.get(args.log_level, logging.INFO)
120
    syslogger = logging.NullHandler() if args.no_syslog else SysLogHandler()
×
121
    handlers.append(syslogger)
×
122
    if args.log_file:
×
123
        handlers.append(logging.FileHandler(args.log_file))
×
124
    logging.handlers = handlers
×
125
    log.setLevel(level)
×
126
    for handler in handlers:
×
127
        log.addHandler(handler)
×
128
    log.info(f"Log level set to {logging.getLevelName(level)}")
×
129

130

131
def main(testargs=None):
×
132
    parser = argparse.ArgumentParser(
×
133
        prog="mender-auth-azure-iot",
134
        description="""mender-auth-azure-iot integrates the mender daemon with the Azure IoT Hub -
135
    tasks performed by the daemon (see list of COMMANDS below).""",
136
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
137
    )
138
    #
139
    # Commands
140
    #
141
    subcommand_parser = parser.add_subparsers(title="COMMANDS")
×
142
    daemon_parser = subcommand_parser.add_parser(
×
143
        "daemon", help="Start the client as a background service."
144
    )
145
    daemon_parser.set_defaults(func=run_daemon)
×
146
    #
147
    # Options
148
    #
149
    global_options = parser.add_argument_group("Global Options")
×
150
    global_options.add_argument(
×
151
        "--log-file", "-L", help="FILE to log to.", metavar="FILE"
152
    )
153
    global_options.add_argument(
×
154
        "--log-level", "-l", help="Set logging to level.", default="info"
155
    )
156
    global_options.add_argument(
×
157
        "--no-syslog",
158
        help="Disble logging to syslog.",
159
        default=False,
160
        action="store_true",
161
    )
162
    global_options.add_argument(
×
163
        "--version", "-v", help="print the version", default=False, action="store_true"
164
    )
165
    args = parser.parse_args(testargs)
×
166
    args.stop = False
×
167
    setup_logging(args)
×
168
    if args.version:
×
169
        run_version(args)
×
170
        return
×
171
    if "func" not in vars(args):
×
172
        parser.print_usage()
×
173
        return
×
174
    if not testargs:
×
175
        args.func(args)
×
176

177

178
if __name__ == "__main__":
×
179
    sys.exit(main())
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc