Add configuration file loading and parsing 65/27365/5
authorDamian Hobson-Garcia <dhobsong@igel.co.jp>
Tue, 5 Apr 2022 03:11:38 +0000 (12:11 +0900)
committerDamian Hobson-Garcia <dhobsong@igel.co.jp>
Wed, 20 Apr 2022 01:58:39 +0000 (10:58 +0900)
Parse the lease configuration information from a configuration file.
Each lease configuration takes a name and list of connectors to
add to the lease.  As long as one connector is found for a given
configuration, the lease will be created.

Bug-AGL: SPEC-3815

Change-Id: Iec4eaf37fba5db17a22e4945de10a06ac94063e4
Signed-off-by: Damian Hobson-Garcia <dhobsong@igel.co.jp>
drm-lease-manager/lease-config.c [new file with mode: 0644]
drm-lease-manager/lease-config.h [new file with mode: 0644]
drm-lease-manager/main.c
drm-lease-manager/meson.build
drm-lease-manager/test/lease-config-test.c [new file with mode: 0644]
drm-lease-manager/test/meson.build
meson.build

diff --git a/drm-lease-manager/lease-config.c b/drm-lease-manager/lease-config.c
new file mode 100644 (file)
index 0000000..abb7fc1
--- /dev/null
@@ -0,0 +1,121 @@
+/* Copyright 2022 IGEL Co., Ltd.
+ *
+ * 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.
+ */
+
+#include "lease-config.h"
+#include "log.h"
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <toml.h>
+
+#define CONFIG_ERROR(x, ...) ERROR_LOG("%s: " x, filename, ##__VA_ARGS__)
+
+static bool populate_connector_names(struct lease_config *config,
+                                    toml_array_t *conns)
+{
+       int cnames = toml_array_nelem(conns);
+       config->connector_names = calloc(cnames, sizeof(char *));
+       if (!config->connector_names) {
+               DEBUG_LOG("Memory allocation failed: %s\n", strerror(errno));
+               return false;
+       }
+
+       config->cnames = cnames;
+
+       for (int i = 0; i < config->cnames; i++) {
+               toml_datum_t conn = toml_string_at(conns, i);
+               if (!conn.ok) {
+                       return false;
+               }
+               config->connector_names[i] = conn.u.s;
+       }
+       return true;
+}
+
+int parse_config(char *filename, struct lease_config **parsed_config)
+{
+       struct lease_config *config = NULL;
+       int nconfigs, i, ret = 0;
+       char parse_error[160];
+
+       FILE *fp = fopen(filename, "r");
+       if (!fp)
+               return 0;
+
+       toml_table_t *t_config =
+           toml_parse_file(fp, parse_error, sizeof parse_error);
+       if (!t_config) {
+               CONFIG_ERROR("configuration file parse error: %s\n",
+                            parse_error);
+               fclose(fp);
+               return 0;
+       }
+
+       toml_array_t *leases = toml_array_in(t_config, "lease");
+       if (!leases) {
+               CONFIG_ERROR(
+                   "Invalid config - cannot find any 'lease' configs");
+               goto err;
+       }
+       nconfigs = toml_array_nelem(leases);
+       config = calloc(nconfigs, sizeof *config);
+
+       if (!config) {
+               DEBUG_LOG("Memory allocation failed: %s\n", strerror(errno));
+               goto err;
+       }
+
+       for (i = 0; i < toml_array_nelem(leases); i++) {
+               toml_table_t *lease = toml_table_at(leases, i);
+
+               toml_datum_t name = toml_string_in(lease, "name");
+               if (!name.ok) {
+                       CONFIG_ERROR("Invalid lease name in entry #%d\n", i);
+                       goto err_free_config;
+               }
+
+               config[i].lease_name = name.u.s;
+
+               toml_array_t *conns = toml_array_in(lease, "connectors");
+               if (conns && !populate_connector_names(&config[i], conns)) {
+                       CONFIG_ERROR("Non string connector name in lease: %s\n",
+                                    config[i].lease_name);
+                       goto err_free_config;
+               }
+       }
+
+       *parsed_config = config;
+       ret = nconfigs;
+err:
+       toml_free(t_config);
+       fclose(fp);
+       return ret;
+err_free_config:
+       release_config(i, config);
+       goto err;
+}
+
+void release_config(int num_leases, struct lease_config *config)
+{
+       for (int i = 0; i < num_leases; i++) {
+               struct lease_config *c = &config[i];
+               free(c->lease_name);
+               for (int j = 0; j < c->cnames; j++)
+                       free(c->connector_names[j]);
+               free(c->connector_names);
+       }
+       free(config);
+}
diff --git a/drm-lease-manager/lease-config.h b/drm-lease-manager/lease-config.h
new file mode 100644 (file)
index 0000000..0760a99
--- /dev/null
@@ -0,0 +1,19 @@
+/* Copyright 2022 IGEL Co., Ltd.
+ *
+ * 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.
+ */
+
+#include "drm-lease.h"
+
+int parse_config(char *filename, struct lease_config **parsed_config);
+void release_config(int num_leasess, struct lease_config *config);
index 2927253..ff69e75 100644 (file)
@@ -13,6 +13,7 @@
  * limitations under the License.
  */
 
+#include "lease-config.h"
 #include "lease-manager.h"
 #include "lease-server.h"
 #include "log.h"
@@ -27,24 +28,28 @@ static void usage(const char *progname)
        printf("Usage: %s [OPTIONS] [<DRM device>]\n\n"
               "Options:\n"
               "-h, --help \tPrint this help\n"
+              "-c, --config \t path to configuration file (default "
+              "/etc/drm-lease-manager.toml)\n"
               "-v, --verbose \tEnable verbose debug messages\n"
               "-t, --lease-transfer \tAllow lease transfter to new clients\n"
               "-k, --keep-on-crash \tDon't close lease on client crash\n",
               progname);
 }
 
-const char *opts = "vtkh";
+const char *opts = "vtkhc:";
 const struct option options[] = {
     {"help", no_argument, NULL, 'h'},
     {"verbose", no_argument, NULL, 'v'},
     {"lease-transfer", no_argument, NULL, 't'},
     {"keep-on-crash", no_argument, NULL, 'k'},
+    {"config", required_argument, NULL, 'c'},
     {NULL, 0, NULL, 0},
 };
 
 int main(int argc, char **argv)
 {
        char *device = "/dev/dri/card0";
+       char *config_file = "/etc/drm-lease-manager.toml";
 
        bool debug_log = false;
        bool can_transfer_leases = false;
@@ -63,6 +68,9 @@ int main(int argc, char **argv)
                case 'k':
                        keep_on_crash = true;
                        break;
+               case 'c':
+                       config_file = optarg;
+                       break;
                case 'h':
                        ret = EXIT_SUCCESS;
                        /* fall through */
@@ -77,7 +85,12 @@ int main(int argc, char **argv)
 
        dlm_log_enable_debug(debug_log);
 
-       struct lm *lm = lm_create(device);
+       struct lease_config *lease_configs = NULL;
+       int num_configs = parse_config(config_file, &lease_configs);
+
+       struct lm *lm =
+           lm_create_with_config(device, num_configs, lease_configs);
+
        if (!lm) {
                ERROR_LOG("DRM Lease initialization failed\n");
                return EXIT_FAILURE;
@@ -145,5 +158,6 @@ int main(int argc, char **argv)
 done:
        ls_destroy(ls);
        lm_destroy(lm);
+       release_config(num_configs, lease_configs);
        return EXIT_FAILURE;
 }
index 7157f01..4732283 100644 (file)
@@ -1,9 +1,10 @@
 
 lease_manager_files = files('lease-manager.c')
 lease_server_files = files('lease-server.c')
+lease_config_files = files('lease-config.c')
 main = executable('drm-lease-manager',
-    [ 'main.c', lease_manager_files, lease_server_files ],
-    dependencies: [ drm_dep, dlmcommon_dep, thread_dep ],
+    [ 'main.c', lease_manager_files, lease_server_files, lease_config_files ],
+    dependencies: [ drm_dep, dlmcommon_dep, thread_dep, toml_dep ],
     install: true,
 )
 
diff --git a/drm-lease-manager/test/lease-config-test.c b/drm-lease-manager/test/lease-config-test.c
new file mode 100644 (file)
index 0000000..fa5edcd
--- /dev/null
@@ -0,0 +1,102 @@
+/* Copyright 2022 IGEL Co., Ltd.
+ *
+ * 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.
+ */
+
+#include "lease-config.h"
+#include <check.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define CONFIG_FILE_TEMPLATE "/tmp/dlmconfig_tmpXXXXXX"
+int config_fd;
+char config_file[] = CONFIG_FILE_TEMPLATE;
+
+static void test_setup(void)
+{
+       strcpy(config_file, CONFIG_FILE_TEMPLATE);
+       config_fd = mkstemp(config_file);
+       ck_assert_int_ge(config_fd, 0);
+}
+
+static void test_shutdown(void)
+{
+       close(config_fd);
+       unlink(config_file);
+}
+
+/* parse config file test */
+/* Test details: Parse a config file
+ * Expected results: a config with the expected results
+ */
+
+START_TEST(parse_leases)
+{
+       ck_assert_ptr_ne(config_file, NULL);
+
+       char test_data[] = "[[lease]]\n"
+                          "name = \"lease 1\"\n"
+                          "connectors = [\"1\", \"b\",\"gamma\" ]\n"
+                          "[[lease]]\n"
+                          "name = \"lease 2\"\n"
+                          "connectors = [\"connector 3\"]\n";
+
+       write(config_fd, test_data, sizeof(test_data));
+
+       struct lease_config *config = NULL;
+       int nconfigs = parse_config(config_file, &config);
+
+       ck_assert_int_eq(nconfigs, 2);
+       ck_assert_ptr_ne(config, NULL);
+
+       ck_assert_str_eq(config[0].lease_name, "lease 1");
+       ck_assert_int_eq(config[0].cnames, 3);
+       ck_assert_str_eq(config[0].connector_names[0], "1");
+       ck_assert_str_eq(config[0].connector_names[1], "b");
+       ck_assert_str_eq(config[0].connector_names[2], "gamma");
+
+       ck_assert_str_eq(config[1].lease_name, "lease 2");
+       ck_assert_int_eq(config[1].cnames, 1);
+       ck_assert_str_eq(config[1].connector_names[0], "connector 3");
+
+       release_config(nconfigs, config);
+}
+END_TEST
+
+static void add_parse_tests(Suite *s)
+{
+       TCase *tc = tcase_create("Config file parsing tests");
+
+       tcase_add_checked_fixture(tc, test_setup, test_shutdown);
+
+       tcase_add_test(tc, parse_leases);
+       suite_add_tcase(s, tc);
+}
+
+int main(void)
+{
+       int number_failed;
+       Suite *s;
+       SRunner *sr;
+
+       s = suite_create("DLM lease manager tests");
+
+       add_parse_tests(s);
+
+       sr = srunner_create(s);
+       srunner_run_all(sr, CK_NORMAL);
+       number_failed = srunner_ntests_failed(sr);
+       srunner_free(sr);
+       return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
index bb97274..8d5c06f 100644 (file)
@@ -32,5 +32,17 @@ lm_test = executable('lease-manager-test',
            c_args: test_c_args,
            include_directories: ls_inc)
 
+lc_objects = main.extract_objects(lease_config_files)
+lc_test_sources = [
+    'lease-config-test.c'
+]
+
+lc_test = executable('lease-config-test',
+           sources: lc_test_sources,
+           objects: lc_objects,
+           dependencies: [check_dep, dlmcommon_dep, toml_dep],
+           include_directories: ls_inc)
+
 test('DRM Lease manager - socket server test', ls_test, is_parallel: false)
 test('DRM Lease manager - DRM interface test', lm_test)
+test('DRM Lease manager - config parse test', lc_test)
index 7f8adf5..c2c88a6 100644 (file)
@@ -35,6 +35,7 @@ configuration_inc = include_directories('.')
 
 drm_dep = dependency('libdrm', version: '>= 2.4.89')
 thread_dep = dependency('threads')
+toml_dep = dependency('libtoml')
 
 enable_tests = get_option('enable-tests')