[Freeipa-devel] Structured DNS record API proposal
Jakub Hrozek
jhrozek at redhat.com
Fri Sep 23 10:32:21 UTC 2011
On Thu, Sep 22, 2011 at 09:59:01PM -0400, Dmitri Pal wrote:
> On 09/22/2011 03:37 AM, Jakub Hrozek wrote:
> > On Thu, Sep 22, 2011 at 08:25:01AM +0200, Jan Cholasta wrote:
> >> On 21.9.2011 23:55, Dmitri Pal wrote:
> >>> On 09/21/2011 10:27 AM, Adam Young wrote:
> >>>> On 09/20/2011 11:11 AM, Martin Kosek wrote:
> >>>>> On Tue, 2011-09-20 at 10:02 -0400, Adam Young wrote:
> >>>>>> This discussion got me thinking, always a dangerous proposal:
> >>>>>>
> >>>>>> We are currently exposing record add with the lie that when you add a
> >>>>>> record, it has a type. THe reality is that a record is just this big
> >>>>>> collection of multi value attributes, and each of those is the "type"
> >>>>>> of the record.
> >>>>> The way I see it is that we have different types of Resource Records
> >>>>> with a (domain) name that can be shared.
> >>>>>
> >>>>>> If all of the 'records' have the same idnsname, then they really fall
> >>>>>> under the same Record object in LDAP.
> >>>>> Yes.
> >>>>>
> >>>>>> What if we focuses on the attribtutes themselves, and add the type info
> >>>>>> there.
> >>>>> I thought we do this already.
> >>>>>
> >>>>>> Pie in the sky proposal. Treat it as a starting point:
> >>>>>>
> >>>>>> From the webui perspective
> >>>>>> dnsrecord-add allows the case where it just has the the idnsname with
> >>>>>> no "records"
> >>>>>>
> >>>>>> dnsrecordattr-mod takes record type specific values.
> >>>>>>
> >>>>>> To add a location entry:
> >>>>>>
> >>>>>> ipa dnsrecordattr-mod --append location --lat-deg=INT --lat-min=INT
> >>>>>> --lat-sec=FLOAT --lat-dir=ENUM --lon-deg=INT --lon-min=INT
> >>>>>> --lon-sec=FLOAT --lon-dir=ENUM --alt=FLOAT --h-precision=FLOAT
> >>>>>> --v-precision=FLOAT
> >>>>>>
> >>>>>>
> >>>>>> And to remove it
> >>>>>>
> >>>>>> ipa dnsrecordattr-mod --remove location --lat-deg=INT --lat-min=INT
> >>>>>> --lat-sec=FLOAT --lat-dir=ENUM --lon-deg=INT --lon-min=INT
> >>>>>> --lon-sec=FLOAT --lon-dir=ENUM --alt=FLOAT --h-precision=FLOAT
> >>>>>> --v-precision=FLOAT
> >>>>> So if user would want to remove a LOC record, he would have to pass all
> >>>>> these attributes to refer which attribute value to remove?
> >>>> I think that is the case anyway. Since a DNS record is really just an
> >>>> multivalue attribute, you would now have to do a dns-record-mod
> >>>> with the list of all LOC records that you don't want to delete. I
> >>>> used this as an example because it is the most complex case.
> >>>>
> >>>> Just thinking it through...I'm not certain I like the "one command per
> >>>> record type" as it changes a lot of other assumptions. DNS is a
> >>>> wierd beast already.
> >>>>
> >>>> I've spent a lot of time on the DNS ui, and it is pretty tricky to
> >>>> get right. I'm trying to balance the PI against efficient usage.
> >>>>
> >>>> What we really need for the fields is a way to specify the format for
> >>>> a given field, much like the format strings used for group names. For
> >>>> example, the LOC record is really
> >>>>
> >>>> <owner> <TTL> <class> LOC d1 [m1 [s1]] {"N"|"S"} d2 [m2 [s2]]
> >>>> {"E"|"W"}
> >>>> alt["m"] [siz["m"] [hp["m"] [vp["m"]]]]
> >>>>
> >>>>
> >>>> And all the WebUI needs is a way to specify that format to validate.
> >>>>
> >>> Can we use augeas for this?
> >>> Augeas lenses use this kind of the validation and there is python
> >>> binding so may be we should use augeas as an inspiration or ask for an
> >>> augeas Javascript solution?
> >> We can't. Augeas knows how to manipulate config files and only that,
> >> there is no API for anything else.
> >>
> > Some time ago I wrote a patch to extend Augeas to operate on arbitrary
> > strings. I never had time to push it upstream, but I think I still have
> > is somewhere.
> >
> > Not sure if this approach would help us anyway, we would still have to
> > wait until this feature made it to RHEL and solve the JS bindings as
> > well
> >
>
> Yes I was thinking about this path at least as an inspiration.
>
OK, I've dug up and attached the patch.
Obviously it doesn't apply upstream anymore, but it is still a very good
starting point if someone wants to tackle this problem.
-------------- next part --------------
>From 191110b81376f831b211e34f491a379d69c79cb0 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Wed, 25 Mar 2009 17:04:54 +0100
Subject: [PATCH] aug_lens_get
---
src/augeas.c | 29 +++++++++++
src/augeas.h | 20 ++++++++
src/augeas_sym.version | 1 +
src/augtool.c | 16 ++++++
src/internal.h | 8 +++
src/transform.c | 121 +++++++++++++++++++++++++++++++++++++----------
src/transform.h | 4 ++
7 files changed, 173 insertions(+), 26 deletions(-)
diff --git a/src/augeas.c b/src/augeas.c
index 192a79a..291906e 100644
--- a/src/augeas.c
+++ b/src/augeas.c
@@ -978,6 +978,35 @@ int aug_print(const struct augeas *aug, FILE *out, const char *pathin) {
return result;
}
+int aug_lens_get(augeas *aug, const char *path, const char *lens,
+ const char *txt, size_t txt_len) {
+ char *text = NULL;
+ int result = -1;
+
+ /* append newline to the end of the string if needed */
+ if (txt_len == 0 || txt[txt_len-1] != '\n') {
+ if (ALLOC_N(text, txt_len+2) < 0) {
+ goto fini;
+ }
+ strcpy(text, txt);
+ text[txt_len] = '\n';
+ text[txt_len+1] = '\0';
+ txt_len += 2;
+ } else {
+ text = (char *) txt;
+ }
+
+ result = transform_string(aug, lens, path, text, txt_len);
+ if (result != 0) {
+ goto fini;
+ }
+
+ result = 0;
+fini:
+ if (text != txt) free(text);
+ return result;
+}
+
void aug_close(struct augeas *aug) {
if (aug == NULL)
return;
diff --git a/src/augeas.h b/src/augeas.h
index 9792bad..435815b 100644
--- a/src/augeas.h
+++ b/src/augeas.h
@@ -250,6 +250,26 @@ int aug_save(augeas *aug);
*/
int aug_load(augeas *aug);
+
+/* Function: aug_lens_get
+ *
+ * Transform the string TXT into a tree using the get direction of lens
+ * LENS and put the resulting tree into the tree in AUG at PATH.
+ *
+ * The PATH must not start with '/augeas', and should not start with
+ * '/files', unless you know very well what you are doing.
+ *
+ * The LENS is the fully qualified name of a lens in the form
+ * 'Module.lens'.
+ *
+ * The string TXT is a nul-terminated string of length TXT_LEN
+ *
+ * Return -1 on error, and 0 on success
+ */
+
+int aug_lens_get(augeas *aug, const char *path, const char *lens,
+ const char *txt, size_t txt_len);
+
/* Function: aug_print
*
* Print each node matching PATH and its descendants to OUT.
diff --git a/src/augeas_sym.version b/src/augeas_sym.version
index 0643904..2236967 100644
--- a/src/augeas_sym.version
+++ b/src/augeas_sym.version
@@ -10,6 +10,7 @@ AUGEAS_0.1.0 {
aug_match;
aug_save;
aug_print;
+ aug_lens_get;
# Symbols with __ are private
__aug_load_module_file;
local: *;
diff --git a/src/augtool.c b/src/augtool.c
index c1ac383..b5ab106 100644
--- a/src/augtool.c
+++ b/src/augtool.c
@@ -251,6 +251,19 @@ static int cmd_get(char *args[]) {
return 0;
}
+static int cmd_lens_get(char *args[]) {
+ const char *path = cleanpath(args[0]);
+ const char *module = cleanpath(args[1]);
+ const char *txt = cleanpath(args[2]);
+ int ret;
+
+ ret = aug_lens_get(aug, path, module, txt, strlen(txt));
+ if(ret != 0)
+ printf ("Failed\n");
+
+ return ret;
+}
+
static int cmd_print(char *args[]) {
return aug_print(aug, stdout, cleanpath(args[0]));
}
@@ -421,6 +434,9 @@ static const struct command const commands[] = {
"Save all pending changes to disk. For now, files are not overwritten.\n"
" Instead, new files with extension .augnew are created"
},
+ { "lens_get", 3, 3, cmd_lens_get, "lens_get <PATH> <LENS> <TEXT>",
+ "Parse text according to LENS and store result at PATH/\n"
+ },
{ "load", 0, 0, cmd_load, "load",
"Load files accordig to the transforms in /augeas/load."
},
diff --git a/src/internal.h b/src/internal.h
index cc636ef..7992fa7 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -63,6 +63,14 @@
* Information about files */
#define AUGEAS_META_FILES AUGEAS_META_TREE AUGEAS_FILES_TREE
+/* Define: AUGEAS_TEXT_TREE
+ * A hierarchy where we keep directly parsed text */
+#define AUGEAS_TEXT_TREE "/text"
+
+/* Degine: AUGEAS_META_TEXT
+ * Information about directly parsed text */
+#define AUGEAS_META_TEXT AUGEAS_META_TREE AUGEAS_TEXT_TREE
+
/* Define: AUGEAS_META_ROOT
* The root directory */
#define AUGEAS_META_ROOT AUGEAS_META_TREE "/root"
diff --git a/src/transform.c b/src/transform.c
index b50a9bb..701f3ed 100644
--- a/src/transform.c
+++ b/src/transform.c
@@ -201,12 +201,12 @@ void free_transform(struct transform *xform) {
free(xform);
}
-static char *err_path(const char *filename) {
+static char *err_path(const char *filename, const char *base) {
char *result = NULL;
if (filename == NULL)
- pathjoin(&result, 2, AUGEAS_META_FILES, s_error);
+ pathjoin(&result, 2, base, s_error);
else
- pathjoin(&result, 3, AUGEAS_META_FILES, filename, s_error);
+ pathjoin(&result, 3, base, filename, s_error);
return result;
}
@@ -252,58 +252,83 @@ calc_line_ofs(const char *text, size_t pos, size_t *line, size_t *ofs)
}
/* Record an error in the tree. The error will show up underneath
- * /augeas/FILENAME/error. PATH is the path to the toplevel node in the
+ * ERROR_NODE. PATH is the path to the toplevel node in the
* tree where the lens application happened. When STATUS is NULL, just
- * clear any error associated with FILENAME in the tree.
+ * clear any error associated with ERROR_NODE in the tree.
*/
static int store_error(struct augeas *aug,
- const char *filename, const char *path,
+ char **error_node, const char *path,
const char *status, int errnum,
const struct lns_error *err, const char *text) {
- char *ep = err_path(filename);
int r;
- int result = -1;
-
- if (ep == NULL)
- return -1;
- aug_rm(aug, ep);
+ aug_rm(aug, *error_node);
if (status != NULL) {
- r = aug_set(aug, ep, status);
+ r = aug_set(aug, *error_node, status);
if (r < 0)
- goto done;
+ return -1;
/* Errors from err_set are ignored on purpose. We try
* to report as much as we can */
if (err != NULL) {
if (err->pos >= 0) {
size_t line, ofs;
- err_set(aug, &ep, s_pos, "%d", err->pos);
+ err_set(aug, error_node, s_pos, "%d", err->pos);
if (text != NULL) {
calc_line_ofs(text, err->pos, &line, &ofs);
- err_set(aug, &ep, s_line, "%zd", line);
- err_set(aug, &ep, s_char, "%zd", ofs);
+ err_set(aug, error_node, s_line, "%zd", line);
+ err_set(aug, error_node, s_char, "%zd", ofs);
}
}
if (err->path != NULL) {
- err_set(aug, &ep, s_path, "%s%s", path, err->path);
+ err_set(aug, error_node, s_path, "%s%s", path, err->path);
}
if (err->lens != NULL) {
char *fi = format_info(err->lens->info);
if (fi != NULL) {
- err_set(aug, &ep, s_lens, "%s", fi);
+ err_set(aug, error_node, s_lens, "%s", fi);
free(fi);
}
}
- err_set(aug, &ep, s_message, "%s", err->message);
+ err_set(aug, error_node, s_message, "%s", err->message);
} else if (errnum != 0) {
const char *msg = strerror(errnum);
- err_set(aug, &ep, s_message, "%s", msg);
+ err_set(aug, error_node, s_message, "%s", msg);
}
}
- result = 0;
- done:
+}
+
+/* Store an error associated to FILENAME under /augeas/FILENAME/error
+ */
+static int store_error_file(struct augeas *aug,
+ const char *filename, const char *path,
+ const char *status, int errnum,
+ const struct lns_error *err, const char *text) {
+ char *ep = err_path(filename, AUGEAS_META_FILES);
+ int result = -1;
+
+ if (ep == NULL)
+ return -1;
+
+ result = store_error(aug, &ep, path, status, errnum, err, text);
+
+ free(ep);
+ return result;
+}
+
+static int store_error_string(struct augeas *aug,
+ const char *string_name, const char *path,
+ const char *status, int errnum,
+ const struct lns_error *err, const char *text) {
+ char *ep = err_path(string_name, AUGEAS_META_TEXT);
+ int result = -1;
+
+ if (ep == NULL)
+ return -1;
+
+ result = store_error(aug, &ep, path, status, errnum, err, text);
+
free(ep);
return result;
}
@@ -417,7 +442,7 @@ static int load_file(struct augeas *aug, struct lens *lens, char *filename) {
result = 0;
done:
- store_error(aug, filename + strlen(aug->root) - 1, path, err_status,
+ store_error_file(aug, filename + strlen(aug->root) - 1, path, err_status,
errno, err, text);
free_lns_error(err);
free(path);
@@ -847,7 +872,7 @@ int transform_save(struct augeas *aug, struct tree *xfm,
{
const char *emsg =
dyn_err_status == NULL ? err_status : dyn_err_status;
- store_error(aug, filename, path, emsg, errno, err, NULL);
+ store_error_file(aug, filename, path, emsg, errno, err, NULL);
}
free(dyn_err_status);
lens_release(lens);
@@ -935,7 +960,7 @@ int remove_file(struct augeas *aug, struct tree *tree) {
{
const char *emsg =
dyn_err_status == NULL ? err_status : dyn_err_status;
- store_error(aug, filename, path, emsg, errno, NULL, NULL);
+ store_error_file(aug, filename, path, emsg, errno, NULL, NULL);
}
free(path);
free(augorig);
@@ -945,6 +970,50 @@ int remove_file(struct augeas *aug, struct tree *tree) {
return -1;
}
+int transform_string(struct augeas *aug, const char *lens_path, const char *basepath,
+ const char *txt, size_t txt_len) {
+ struct info *info = NULL;
+ struct lns_error *err = NULL;
+ struct tree *tree = NULL;
+ int result = -1;
+ const char *err_status = NULL;
+ struct lens *lens = NULL;
+ char *path = NULL;
+
+ pathjoin(&path, 2, AUGEAS_TEXT_TREE, basepath);
+
+ lens = lens_from_name(aug, lens_path);
+ if(lens == NULL) {
+ goto done;
+ }
+
+ make_ref(info);
+ info->first_line = 1;
+ info->last_line = 1;
+ info->first_column = 1;
+ info->last_column = txt_len;
+
+ tree = lns_get(info, lens, txt, &err);
+ if (err != NULL) {
+ err_status = "parse_failed";
+ goto done;
+ }
+
+ unref(info, info);
+
+ tree_replace(aug->origin, path, tree);
+ tree = NULL;
+
+ result = 0;
+done:
+ store_error_string(aug, basepath, path, err_status,
+ errno, err, txt);
+ free(path);
+ free_tree(tree);
+ free_lns_error(err);
+ return result;
+}
+
/*
* Local variables:
* indent-tabs-mode: nil
diff --git a/src/transform.h b/src/transform.h
index 1178f64..d6fb841 100644
--- a/src/transform.h
+++ b/src/transform.h
@@ -87,6 +87,10 @@ int transform_save(struct augeas *aug, struct tree *xfm,
* Return 0 on success, -1 on failure
*/
int remove_file(struct augeas *aug, struct tree *tree);
+
+int transform_string(struct augeas *aug, const char *lens, const char *basepath,
+ const char *txt, size_t txt_len);
+
#endif
--
1.7.6.2
More information about the Freeipa-devel
mailing list