Skip to content
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

lib: use an explicit parser context #233

Merged
merged 20 commits into from
Nov 24, 2021

Conversation

schopin-pro
Copy link
Contributor

@schopin-pro schopin-pro commented Sep 24, 2021

Description

Instead of directly writing into the final network state, use a separate
global parser object to store any intermediate data needed during
parsing. This allows us to ensure that the client can only see valid
configurations, as the parser is opaque to the client, who then must
call our functions to import and validate the data into the final
network state.

Since the public API doesn't allow us to pass around some context, we
still store a static object to use in those APIs, but all the internal
functions shouldn't touch any external data.

This PR depends on #229 and #227 and is only a prequel to the proper YAML
parser unification work, which will start with the removal of the current parsing
API, replaced by one based on explicitly allocated states, in conjunction with
the #232 work. To make things easier, the latter PR has been added as a dependency
for this one.

It also picked up a dependency on #234 along the way :)

Only the commits after the merge commit are part of the PR proper, the rest are
from the dependencies.

Checklist

  • Runs make check successfully.
  • Retains 100% code coverage (make check-coverage).
  • New/changed keys in YAML format are documented.
  • Address the FIXME regarding the missing_id system

@schopin-pro schopin-pro marked this pull request as draft September 24, 2021 17:21
@codecov-commenter
Copy link

codecov-commenter commented Sep 24, 2021

Codecov Report

Merging #233 (adde219) into main (15c98fe) will decrease coverage by 0.01%.
The diff coverage is 100.00%.

❗ Current head adde219 differs from pull request most recent head 9e4d3eb. Consider uploading reports for the commit 9e4d3eb to get more accurate results
Impacted file tree graph

@@            Coverage Diff             @@
##             main     #233      +/-   ##
==========================================
- Coverage   99.10%   99.09%   -0.02%     
==========================================
  Files          58       58              
  Lines        9810     9913     +103     
==========================================
+ Hits         9722     9823     +101     
- Misses         88       90       +2     
Impacted Files Coverage Δ
src/parse.c 99.81% <ø> (-0.19%) ⬇️
netplan/cli/utils.py 100.00% <100.00%> (ø)
src/abi_compat.c 100.00% <100.00%> (ø)
src/error.c 100.00% <100.00%> (ø)
src/generate.c 100.00% <100.00%> (ø)
src/netplan.c 100.00% <100.00%> (ø)
src/networkd.c 100.00% <100.00%> (ø)
src/parse-nm.c 100.00% <100.00%> (ø)
src/types.c 100.00% <100.00%> (ø)
src/util.c 100.00% <100.00%> (ø)
... and 14 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 15c98fe...9e4d3eb. Read the comment docs.

@schopin-pro schopin-pro force-pushed the netplan-parser-struct branch 5 times, most recently from a43e613 to 5c58924 Compare September 30, 2021 16:41
@schopin-pro schopin-pro force-pushed the netplan-parser-struct branch 8 times, most recently from 5b58f58 to 3e75a6b Compare October 12, 2021 16:36
Copy link
Collaborator

@slyon slyon left a comment

Choose a reason for hiding this comment

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

This PR is still in DRAFT state, but still I left a few inline comments.

include/parse-nm.h Show resolved Hide resolved
include/parse.h Show resolved Hide resolved
include/parse.h Show resolved Hide resolved
src/abi_compat.c Show resolved Hide resolved
src/abi_compat.c Show resolved Hide resolved
src/types.h Show resolved Hide resolved
src/util.c Outdated Show resolved Hide resolved
src/util.c Outdated Show resolved Hide resolved
src/util.c Outdated Show resolved Hide resolved
src/yaml-helpers.h Show resolved Hide resolved
Copy link
Collaborator

@slyon slyon left a comment

Choose a reason for hiding this comment

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

This PR is still in DRAFT state, but still I left a few inline comments.

@schopin-pro
Copy link
Contributor Author

Note that while the Codecov report says I'm missing some coverage, the fact that the unit tests passed means that make check-coverage succeeded. I'm guessing Codecov has lost track of which commit is at the tip of the PR.

…ucts

We already have the functions to actually free the objects, these
helpers just wrap those to also clear up the *pointer* and nullifying
it.

These functions are going to be used in the parser code to clear
intermediate state, notably on the error paths.

Function names, signature and implementations are heavily inspired by
g_datalist_clear().

V2:
rename the functions to match the new scheme [prefix_]type_action
Keeping a pointer around after we've transferred ownership of the data
to a netdef is a recipy for disaster, as we have no way of knowing if
we're still responsible for cleaning up the NetplanAddressOptions
object.
`error` is usually a GError** argument, and the new name is just as
legible.
This allows us to shift the code left, make it easier to read.
The function is supposed to work on an already empty state, as it parses
a whole tree and validates it afterwards. We thus clear it explicitly.

This is a latent bug that might become apparent should the validation be
a little more stringent, such as redefinition of already existing
netdefs.
… dependency

Some tests were relying on the state having been cleared in a previous
state, which isn't necessarily the case.
While the current approach works for now, it'll break when we separate
parser state and global state, until we do the actual validation.
Instead of directly writing into the final network state, use a separate
global parser object to store any intermediate data needed during
parsing. This allows us to ensure that the client can only see valid
configurations, as the parser is opaque to the client, who then must
call our functions to import *and validate* the data into the final
network state.

Since the public API doesn't allow us to pass around some context, we
still store a static object to use in those APIs, but all the internal
functions shouldn't touch any external data.

V2:
* Remove stray cur_filename global variable
* Fix some formatting
* Rename 'done' field to 'parsed_defs'
* Reduced the nocov zone
The netplan_finish_parse implementation is moved to our ABI attic,
abi_compat.c, and is now a simple wrapper around
netplan_state_import_parser_results, which is the new function used to
import into a Netplan state the results of a parsing operations. As
before, the idea is to maintain a constantly valid Netplan state, so
this function does validation before import.
The old functions have been rewritten as wrappers around the new APIs

V2:
* Add some header comments to the new functions
…new API scheme

There are no process_input_file() replacement as it can very well be
written by the client code. process_yaml_hierarchy() has been replaced
by a function in utils, netplan_parser_load_yaml_hierarchy(), which
leaves the error policy up to the client code rather than calling
exit().

The old versions have been moved to abi_compat.c and reimplemented to
keep their previous semantics.
This function is only there for legacy reasons, and should be replaced
by a normalized API.
This is an old API. The ABI compat version is entirely reimplemented
using public, up-to-date functions.
This new implementation does away with global state, creating its own
local state instead.

V2: fix formatting
This makes it possible to use the wrapper class in autonomy, and remove
the implicit dependency between the netplan_get_ids_for_devtype tests
and the _NetdefIdIterator tests. The latter would crash if run before
the former, as the ctypes bindings wouldn't have been initialized.
THis call meant that the network file was generated using the global
state as reference instead of the local np_state, making things such as
the VLAN feature basically useless.
This allows us to do proper cleanup on error cases.

Note that since generate was the only consumer of some of the legacy
APIs, those endpoints are not hit by the testsuite anymore and are thus
marked as ignored by the coverage calculations.
Copy link
Collaborator

@slyon slyon left a comment

Choose a reason for hiding this comment

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

Thank you Simon for handling all those comments properly. Another PR that is moving us a big step forward, kudos!

I was able to successfully run the autopkgtests locally, incl. 1 run in "ABI compat" mode (new libnetplan, old binaries).

ACK, Codecov is fine, it is only complaining because of those lines (it does not recognize the LCOV_EXCL_* stanzas):

    //LCOV_EXCL_START		
    if (npp->ids_in_file) {	
        g_hash_table_destroy(npp->ids_in_file);		
        npp->ids_in_file = NULL;		
    //LCOV_EXCL_STOP

https://app.codecov.io/gh/canonical/netplan/compare/233/tree/src/parse.c

@slyon slyon merged commit 715cb2c into canonical:main Nov 24, 2021
@schopin-pro schopin-pro deleted the netplan-parser-struct branch April 13, 2022 09:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants