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: introduce the notion of NetplanState #232

Merged
merged 1 commit into from
Oct 12, 2021

Conversation

schopin-pro
Copy link
Contributor

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

Description

This would be a structure holding all the data used to define a complete
network setup in Netplan. At this moment there are no guarantee of
coherence or validation of the validation, though.

We use some linker tricks to keep the previous globals netdef,
netdef_ordered and global_ovs_config visible in the ABI, even though
they now actually point to fields within a global state instance that
is there only for this compatibility purpose.

Note that the constructor, destructor and netdef accessors aren't
implemented yet. This is mostly because there are no consumers for this
API yet, and I'd like to get this commit into the mainline as is, which
means retaining 100% code coverage... ¯_(ツ)_/¯

This PR actually consists of a single commit, but depends on both #227 and #228,
which are both merged via an explicit merge commit in order to mark the separation
from the actual history to review.

Checklist

  • Runs make check successfully.
  • Retains 100% code coverage (make check-coverage).
  • New/changed keys in YAML format are documented.
  • (Optional) Adds example YAML for new feature.
  • (Optional) Closes an open bug in Launchpad.

abicompat.lds Outdated Show resolved Hide resolved
@codecov-commenter
Copy link

codecov-commenter commented Sep 27, 2021

Codecov Report

Merging #232 (cac0ec2) into main (bc6eb0b) will decrease coverage by 0.01%.
The diff coverage is 92.85%.

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

@@            Coverage Diff             @@
##             main     #232      +/-   ##
==========================================
- Coverage   99.06%   99.04%   -0.02%     
==========================================
  Files          57       58       +1     
  Lines        9706     9713       +7     
==========================================
+ Hits         9615     9620       +5     
- Misses         91       93       +2     
Impacted Files Coverage Δ
src/types.c 99.06% <88.88%> (-0.94%) ⬇️
src/abi_compat.c 100.00% <100.00%> (ø)
src/parse.c 100.00% <100.00%> (ø)

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 bc6eb0b...dbe26f6. Read the comment docs.

@schopin-pro schopin-pro force-pushed the netplanstate-struct branch 4 times, most recently from bab7f7b to 836e817 Compare September 30, 2021 12:44
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.

Nice, I really like your approach of using a linker script to keep the ABI stable!

Overall, I'm +1 on this, but left a few inline comments, mostly about naming/API design that we should somehow agree upon.

Let me know what you think!

And again: I will run the integration tests with new lib + old binary to check for compatibility.

src/parse.c Outdated Show resolved Hide resolved
src/parse.c Outdated Show resolved Hide resolved
src/types.c Outdated Show resolved Hide resolved
src/types.c Outdated Show resolved Hide resolved
include/netplan.h Outdated Show resolved Hide resolved
include/netplan.h Outdated Show resolved Hide resolved
src/parse.c Outdated Show resolved Hide resolved
src/parse.c Show resolved Hide resolved
src/abi_compat.c Outdated Show resolved Hide resolved
@slyon
Copy link
Collaborator

slyon commented Sep 30, 2021

ABI stability still looking good, passing the autopkgtests with new lib + old binary:

autopkgtest [17:23:59]: @@@@@@@@@@@@@@@@@@@@ summary
ovs                  PASS
ethernets            PASS
bridges              PASS
bonds                PASS
routing              PASS
vlans                PASS
wifi                 FLAKY non-zero exit status 1
tunnels              PASS
scenarios            PASS
regressions          PASS
autostart            PASS
cloud-init           PASS

@schopin-pro
Copy link
Contributor Author

schopin-pro commented Oct 7, 2021

V2:

  • rename the nps arguments to np_state
  • use a netplan_state_* naming scheme for all functions pertaining to
    the new structure
  • Add placeholder implementations for netplan_state_{new,clear}
  • Add a comment in netplan_state_reset regarding the ownership of netdef
    objects
  • Remove superfluous headers in abi_compat.c
  • Remove the dependency on the error-code-flow branch

This would be a structure hodling all the data used to define a complete
network setup in Netplan. At this moment there are no guarantee of
coherence or validation of the validation, though.

We use some linker tricks to keep the previous globals `netdef`,
`netdef_ordered` and `global_ovs_config` visible in the ABI, even though
they now actually point to fields within a global state instance that
is there only for this compatibility purpose.

Note that the constructor, destructor and netdef accessors aren't
implemented yet. This is mostly because there are no consumers for this
API yet, and I'd like to get this commit into the mainline as is, which
means retaining 100% code coverage... ¯\_(ツ)_/¯

V2:
* rename the nps arguments to np_state
* use a netplan_state_* naming scheme for all functions pertaining to
  the new structure
* Add placeholder implementations for netplan_state_{new,clear}
* Add a comment in netplan_state_reset regarding the ownership of netdef
  objects
* Remove superfluous headers in abi_compat.c
* Remove the dependency on the error-code-flow branch

V3:
* Disable LCOV coverage on the placeholder functions
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 for the V2 changes! LGTM, let's move on with this.

@slyon slyon merged commit 9531dad into canonical:main Oct 12, 2021
slyon added a commit that referenced this pull request Oct 19, 2021
New APIs for the generator APIs of libnetplan, with proper error handling and support for the NetplanState feature.

API and ABI compatibility is retained for now. Depends on #232 and #234, as usual see the commits after the merge.

COMMITS:
* lib: networkd: normalize the API with proper error handling

Note that we duplicated a function, as I'd like to remove it from the
API seeing as it's really not netplan-specific, but we need to keep it
in the ABI.

The new API has the ability to report on errors, which allows us to
remove all the calls to exit() within networkd.c. Those have nothing to
do in library code.

We also followed the current convention of using the return value to
signal errors, forcing us to use an out-parameter for the
"has_been_written" return value.

* lib: nm: normalize the API with error handling

The NM generator directly called exit() when something went wrong, which
is not ideal in library code!

We copied the API from the netword generator, hence the has_been_written
new capability.

* lib: openvswitch: normalize the API with proper error handling

The API is now the same as for the networkd and NM generators.

No more exit()ing in the middle of a library call!

* openvswitch: formatting cleanup
* test_routing: fix coverage
* nm: formatting cleanup
* generate: do not drop comments
* networkd: formatting & comments

Co-authored-by: Lukas Märdian <[email protected]>
slyon pushed a commit that referenced this pull request Nov 24, 2021
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.

COMMITS:
* lib: new functions *_clear to safely clear heap-allocated complex structs

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

* parse: clear the cur_addr_options pointer once the parsing is done

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.

* lib: yaml: change the error goto label to err_path

`error` is usually a GError** argument, and the new name is just as
legible.

* lib: write_netplan_conf_full: use an early-return

This allows us to shift the code left, make it easier to read.

* lib: util: netplan_delete_connection: clear the state at the beginning

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.

* tests: clear the global state in teardowns to expose inter-test order dependency

Some tests were relying on the state having been cleared in a previous
state, which isn't necessarily the case.

* cli/utils: force a full parse cycle before extracting ids by devtype

While the current approach works for now, it'll break when we separate
parser state and global state, until we do the actual validation.

* lib: use an explicit parser context

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

* libnetplan: rewrite netplan_finish_parse using explicit states

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.

* lib: expose new functions to generate YAML from Netplan state or defs

The old functions have been rewritten as wrappers around the new APIs

V2:
* Add some header comments to the new functions

* parse-nm: new API using the separate parser state

* lib: add accessors to be able to reach filename from netdef ID

* lib: rewrite process_input_file and process_yaml_hierarchy using the 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.

* lib: move _write_netplan_conf to the abi_compat.c file

This function is only there for legacy reasons, and should be replaced
by a normalized API.

* lib: netplan_get_filename_by_id: move to abi_compat.c

This is an old API. The ABI compat version is entirely reimplemented
using public, up-to-date functions.

* lib: util: reimplement netplan_delete_connection with the new APIs

This new implementation does away with global state, creating its own
local state instead.

V2: fix formatting

* netplan:utils: mark the exception path of the devtype iter as nocover

* netplan/cli/utils: move the iter ABI check in the wrapper class

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.

* lib: networkd: fix a stray call to an old API

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.

* generate: migrate to the new libnetplan APIs

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.
@schopin-pro schopin-pro deleted the netplanstate-struct branch April 13, 2022 09:04
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