Skip to content

[Nexthop][fboss2-dev] Replace file-based config versioning with Git#825

Closed
benoit-nexthop wants to merge 1 commit intofacebook:mainfrom
nexthop-ai:fboss2-cli-prototype_part15
Closed

[Nexthop][fboss2-dev] Replace file-based config versioning with Git#825
benoit-nexthop wants to merge 1 commit intofacebook:mainfrom
nexthop-ai:fboss2-cli-prototype_part15

Conversation

@benoit-nexthop
Copy link
Contributor

@benoit-nexthop benoit-nexthop commented Jan 20, 2026

Pre-submission checklist

  • I've ran the linters locally and fixed lint errors related to the files I modified in this PR. You can install the linters by running pip install -r requirements-dev.txt && pre-commit install
  • pre-commit run

Summary

Replace the basic file-based configuration versioning mechanism with Git-based versioning for the CLI config session.

Key changes:

  • Add new Git class providing a simple interface for Git operations: init, commit, log, show, etc
  • Use folly::Subprocess with full path /usr/bin/git for all Git commands
  • Replace revision files (agent-rN.conf + symlink) with atomic writes to agent.conf tracked in a local Git repository
  • Use Git commit SHAs as revision identifiers instead of rN format
  • Update RevisionList validation to accept Git SHAs (7+ hex chars)

Repository initialization:

  • Automatically initialize Git repo if it doesn't exist
  • Automatically create initial commit if repo has no commits but config file exists
  • Use --shared=group flag and umask 0002 to ensure .git directory is group-writable when /etc/coop is group-writable

Commands updated:

  • config history: Shows Git commit log with SHA, author, timestamp, message
  • config session diff: Uses git show to compare commits
  • config session commit: Creates Git commits with username as author
  • config rollback: Reads config from Git history and creates new commit

Note: this change is part of a series, the previous one is #809, the next one is #832.

Test Plan

Test updates:

  • Update all CLI config tests to use Git-based setup
  • Initialize Git repo and create initial commit in test fixtures
  • Added new unit tests for the Git layer

Sample usage

Simple change and session commit:

[admin@fboss101 benoit]$ ./fboss2-dev show interface eth1/1/1
+-----------+--------+-------+------+------+------------------------------+-------------+
| Interface | Status | Speed | VLAN | MTU  | Addresses                    | Description |
-----------------------------------------------------------------------------------------
| eth1/1/1  | down   | 800G  | 2001 | 9000 | 10.0.0.0/24                  | demo        |
|           |        |       |      |      | 2400::/64                    |             |
|           |        |       |      |      | fe80::b4db:91ff:fe95:ff07/64 |             |
-----------------------------------------------------------------------------------------
[admin@fboss101 benoit]$ ./fboss2-dev config interface eth1/1/1 description hello
Successfully set description for interface(s) eth1/1/1
[admin@fboss101 benoit]$ ./fboss2-dev config session diff
--- current live config
+++ session config
@@ -2200,7 +2200,7 @@
     "ports": [
       {
         "conditionalEntropyRehash": false,
-        "description": "demo",
+        "description": "hello",
         "drainState": 0,
         "expectedLLDPValues": {
           "2": "eth1/5/1"
[admin@fboss101 benoit]$ ./fboss2-dev config session commit
Config session committed successfully as b8245b4 and config reloaded.
[admin@fboss101 benoit]$ ./fboss2-dev config history | head
 Commit    Author  Commit Time              Message                
------------------------------------------------------------------------
 b8245b40  admin   2026-01-21 11:13:57  Config commit by admin        
 7241abad  admin   2026-01-21 11:12:51  Config commit by admin        
 02fe511c  admin   2026-01-21 10:51:36  Config commit by admin        
 e5650a98  admin   2026-01-21 10:51:35  Config commit by admin        
 ad07138f  admin   2026-01-21 10:51:35  Config commit by admin        
 1845e710  admin   2026-01-21 10:51:35  Config commit by admin        
 ede5a527  admin   2026-01-20 14:28:10  Config commit by admin        
 e900ef88  admin   2026-01-20 14:23:25  Config commit by admin   
[admin@fboss101 benoit]$ cd /etc/coop
[admin@fboss101 coop]$ git -c safe.directory=/etc/coop show
commit b8245b40b2b3c8797cbeed2fb91161e5440b7fd9 (HEAD -> main)
Author: admin <fboss-cli@localhost>
Date:   Wed Jan 21 11:13:57 2026 -0800

    Config commit by admin

diff --git a/cli/agent.conf b/cli/agent.conf
index 406b341..f61516f 100644
--- a/cli/agent.conf
+++ b/cli/agent.conf
@@ -2200,7 +2200,7 @@
     "ports": [
       {
         "conditionalEntropyRehash": false,
-        "description": "demo",
+        "description": "hello",
         "drainState": 0,
         "expectedLLDPValues": {
           "2": "eth1/5/1"
diff --git a/cli/cli_metadata.json b/cli/cli_metadata.json
index 68f340a..6c6a925 100644
--- a/cli/cli_metadata.json
+++ b/cli/cli_metadata.json
@@ -1,6 +1,6 @@
 {
   "action": {},
   "commands": [
-    "config interface eth1/1/1 description demo"
+    "config interface eth1/1/1 description hello"
   ]
 }
\ No newline at end of file

Rollback flow:

[admin@fboss101 benoit]$ ./fboss2-dev config interface eth1/1/1 description hello2
Successfully set description for interface(s) eth1/1/1
[admin@fboss101 benoit]$ ./fboss2-dev config session commit
Config session committed successfully as 476f9ee and config reloaded.
[admin@fboss101 benoit]$ ./fboss2-dev config history | head
 Commit    Author  Commit Time              Message                
------------------------------------------------------------------------
 476f9ee4  admin   2026-01-21 11:15:23  Config commit by admin        
 b8245b40  admin   2026-01-21 11:13:57  Config commit by admin        
 7241abad  admin   2026-01-21 11:12:51  Config commit by admin      <-- we're going to rollback to here
 02fe511c  admin   2026-01-21 10:51:36  Config commit by admin        
 e5650a98  admin   2026-01-21 10:51:35  Config commit by admin        
 ad07138f  admin   2026-01-21 10:51:35  Config commit by admin        
 1845e710  admin   2026-01-21 10:51:35  Config commit by admin        
 ede5a527  admin   2026-01-20 14:28:10  Config commit by admin        
[admin@fboss101 benoit]$ ./fboss2-dev config rollback 7241abad
Successfully rolled back. New commit: 8be163e7. Config reloaded.
[admin@fboss101 benoit]$ ./fboss2-dev show interface eth1/1/1
+-----------+--------+-------+------+------+------------------------------+-------------+
| Interface | Status | Speed | VLAN | MTU  | Addresses                    | Description |
-----------------------------------------------------------------------------------------
| eth1/1/1  | down   | 800G  | 2001 | 9000 | 10.0.0.0/24                  | demo        |
|           |        |       |      |      | 2400::/64                    |             |
|           |        |       |      |      | fe80::b4db:91ff:fe95:ff07/64 |             |
-----------------------------------------------------------------------------------------
[admin@fboss101 benoit]$ ./fboss2-dev config history | head
 Commit    Author  Commit Time          Message                       
---------------------------------------------------------------------------
 8be163e7  admin   2026-01-21 11:17:26  Rollback to 7241abad by admin 
 476f9ee4  admin   2026-01-21 11:15:23  Config commit by admin        
 b8245b40  admin   2026-01-21 11:13:57  Config commit by admin        
 7241abad  admin   2026-01-21 11:12:51  Config commit by admin        
 02fe511c  admin   2026-01-21 10:51:36  Config commit by admin        
 e5650a98  admin   2026-01-21 10:51:35  Config commit by admin        
 ad07138f  admin   2026-01-21 10:51:35  Config commit by admin        
 1845e710  admin   2026-01-21 10:51:35  Config commit by admin    
[admin@fboss101 benoit]$ cd /etc/coop
[admin@fboss101 coop]$ git -c safe.directory=/etc/coop show
commit 8be163e7cd60574278dc7201b157e4238fa55380 (HEAD -> main)
Author: admin <fboss-cli@localhost>
Date:   Wed Jan 21 11:17:26 2026 -0800

    Rollback to 7241abad by admin

diff --git a/cli/agent.conf b/cli/agent.conf
index d918bae..406b341 100644
--- a/cli/agent.conf
+++ b/cli/agent.conf
@@ -2200,7 +2200,7 @@
     "ports": [
       {
         "conditionalEntropyRehash": false,
-        "description": "hello2",
+        "description": "demo",
         "drainState": 0,
         "expectedLLDPValues": {
           "2": "eth1/5/1"
diff --git a/cli/cli_metadata.json b/cli/cli_metadata.json
index 5435c54..68f340a 100644
--- a/cli/cli_metadata.json
+++ b/cli/cli_metadata.json
@@ -1,6 +1,6 @@
 {
   "action": {},
   "commands": [
-    "config interface eth1/1/1 description hello2"
+    "config interface eth1/1/1 description demo"
   ]
 }
\ No newline at end of file

@meta-cla meta-cla bot added the CLA Signed label Jan 20, 2026
@benoit-nexthop benoit-nexthop force-pushed the fboss2-cli-prototype_part15 branch 5 times, most recently from c468783 to 81eaba1 Compare January 23, 2026 09:59
@benoit-nexthop benoit-nexthop force-pushed the fboss2-cli-prototype_part15 branch 2 times, most recently from 3c9d00a to af5398a Compare January 28, 2026 18:48
meta-codesync bot pushed a commit that referenced this pull request Feb 20, 2026
Summary:
**Pre-submission checklist**
- [x] I've ran the linters locally and fixed lint errors related to the files I modified in this PR. You can install the linters by running `pip install -r requirements-dev.txt && pre-commit install`
- [x] `pre-commit run`

Now every config command is saved in the CLI session metadata so we can
easily tell what commands were used in a given session. The metadata is
now also saved along the config when we commit the session. A future
commit will make rollback also rely on this metadata to decide whether
or not to restart the agent.

Note: this change is part of a series, the previous one is #805, the next one is #825.

Pull Request resolved: #809

Test Plan:
New unit tests added.

## Sample usage

```
[admin@fboss101 ~]$ ~/benoit/fboss2-dev config interface eth1/1/1 description this is a test.
Successfully set description for interface(s) eth1/1/1
[admin@fboss101 ~]$ ~/benoit/fboss2-dev config interface eth1/1/1 mtu 1500
Successfully set MTU for interface(s) eth1/1/1 to 1500
[admin@fboss101 ~]$ ls -l ~/.fboss2/
total 216
-rw-r--r-- 1 admin admin 213174 Jan 13 13:00 agent.conf
-rw-r--r-- 1 admin admin    141 Jan 13 13:00 conf_metadata.json
[admin@fboss101 ~]$ cat ~/.fboss2/conf_metadata.json
{
  "action": {},
  "commands": [
    "config interface eth1/1/1 description this is a test.",
    "config interface eth1/1/1 mtu 1500"
  ]
}
[admin@fboss101 ~]$ ~/benoit/fboss2-dev config session commit
Config session committed successfully as r6 and config reloaded.
[admin@fboss101 ~]$ ls -l /etc/coop/cli/
total 1292
-rw-r--r-- 1 root  root  213185 Jan 13 12:52 agent-r1.conf
-rw-r--r-- 1 admin admin 213194 Jan 13 12:56 agent-r2.conf
-rw-r--r-- 1 admin admin    108 Jan 13 12:56 agent-r2.metadata.json
-rw-r--r-- 1 admin admin 213185 Jan 13 12:56 agent-r3.conf
-rw-r--r-- 1 admin admin     99 Jan 13 12:56 agent-r3.metadata.json
-rw-r--r-- 1 admin admin 213185 Jan 13 12:58 agent-r4.conf
-rw-r--r-- 1 admin admin     80 Jan 13 12:58 agent-r4.metadata.json
-rw-r--r-- 1 admin admin 213185 Jan 13 12:58 agent-r5.conf
-rw-r--r-- 1 admin admin     80 Jan 13 12:58 agent-r5.metadata.json
-rw-r--r-- 1 admin admin 213174 Jan 13 13:00 agent-r6.conf
-rw-r--r-- 1 admin admin    141 Jan 13 13:00 agent-r6.metadata.json
[admin@fboss101 ~]$ cat /etc/coop/cli/agent-r6.metadata.json
{
  "action": {},
  "commands": [
    "config interface eth1/1/1 description this is a test.",
    "config interface eth1/1/1 mtu 1500"
  ]
}
```

Reviewed By: KevinYakar

Differential Revision: D93669865

Pulled By: joseph5wu

fbshipit-source-id: 9c37dfd88a59d8e76bdb09f30d0c55897c4e889f
@benoit-nexthop benoit-nexthop force-pushed the fboss2-cli-prototype_part15 branch from af5398a to d4f6898 Compare February 28, 2026 01:34
@benoit-nexthop benoit-nexthop requested review from a team as code owners February 28, 2026 01:34
Replace the basic file-based configuration versioning mechanism with
Git-based versioning for the CLI config session.

Key changes:

- Add new Git class (Git.h/cpp) providing a simple interface for Git
  operations: init, commit, log, show, resolveRef, getHead, hasCommits
- Use folly::Subprocess with full path /usr/bin/git for all Git commands
- Replace revision files (agent-rN.conf + symlink) with atomic writes
  to agent.conf tracked in a local Git repository
- Use Git commit SHAs as revision identifiers instead of rN format
- Update RevisionList validation to accept Git SHAs (7+ hex chars)

Repository initialization:
- Automatically initialize Git repo if it doesn't exist
- Automatically create initial commit if repo has no commits but
  config file exists
- Use --shared=group flag and umask 0002 to ensure .git directory
  is group-writable when /etc/coop is group-writable

Commands updated:
- config history: Shows Git commit log with SHA, author, timestamp, message
- config session diff: Uses git show to compare commits
- config session commit: Creates Git commits with username as author
- config rollback: Reads config from Git history and creates new commit

Test updates:
- Update all CLI config tests to use Git-based setup
- Initialize Git repo and create initial commit in test fixtures
@benoit-nexthop benoit-nexthop force-pushed the fboss2-cli-prototype_part15 branch from d4f6898 to b8b37f2 Compare March 2, 2026 21:29
@meta-codesync
Copy link

meta-codesync bot commented Mar 2, 2026

@joseph5wu has imported this pull request. If you are a Meta employee, you can view this in D94975358.

Copy link
Contributor

@joseph5wu joseph5wu left a comment

Choose a reason for hiding this comment

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

There're some improvement comments about how to properly manage the full sha vs short sha, to avoid mis-using them in your code. Please consider to improve the logic in the future PRs.
I'll land this PR for now to unblock your rebase effort


// Build message based on what actions were taken
std::string message;
std::string shortSha = result.commitSha.substr(0, 7);
Copy link
Contributor

Choose a reason for hiding this comment

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

Would like to see a common utility function for getShortSha(const std::string& commitSha).
Or a more organized way to getFullSha() or getShortSha() from the result.
This will avoid mis-using the wrong sha string.
Could be addressed in future diff

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just to be clear, you can always use the long or the short sha1, as long as it's a unique prefix (just like when using git directly). But other than that, yes, we can add a little helper function to clip the string.

throw std::runtime_error(
"Failed to read current config from " + cliConfigPath);
}
return {content, "current live config"};
Copy link
Contributor

Choose a reason for hiding this comment

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

Will it be a problem that you don't give a shortSha of the current revision here?
In line 42, you always return shortSha revision for non-current case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You can pass anything that git will accept: short sha1, full sha1, branch or tag name, any other ref...

Comment on lines +41 to +42
std::string content = git.fileAtRevision(resolvedSha, "cli/agent.conf");
return {content, revision.substr(0, 8)};
Copy link
Contributor

Choose a reason for hiding this comment

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

Now I think your Git can have to provide a getShortSha()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes it's inconsistent with the other file, good catch. It doesn't matter in practice but I agree it would be better to be consistent. We can fix this in this PR if you want, it's such a small change it wouldn't hurt anything.

@meta-codesync
Copy link

meta-codesync bot commented Mar 3, 2026

@joseph5wu merged this pull request in 307355c.

meta-codesync bot pushed a commit that referenced this pull request Mar 5, 2026
…esolution (#832)

Summary:
**Pre-submission checklist**
- [x] I've ran the linters locally and fixed lint errors related to the files I modified in this PR. You can install the linters by running `pip install -r requirements-dev.txt && pre-commit install`
- [x] `pre-commit run`

When multiple users have concurrent config sessions, the first user to commit succeeds, but subsequent users get an error because their session is based on a stale commit. Previously, whoever committed last would overwrite changes of other users that committed before them.

This commit adds a `config session rebase` command that:
1. Takes the diff between the config as of the base commit and the session
2. Re-applies this diff on top of the current HEAD (similar to git rebase)
3. Uses a recursive 3-way merge algorithm for JSON objects
4. Detects and reports conflicts at specific JSON paths
5. Updates the session's base to the current HEAD on success

The 3-way merge algorithm handles:
- Objects: recursively merges each key
- Arrays: element-by-element merge if sizes match
- Scalars: conflict if both head and session changed differently from base

Note: this change is part of a series, the previous one is #825, the next one is #837.

Pull Request resolved: #832

Test Plan:
Add unit tests covering:
- Successful rebase with non-conflicting changes
- Rebase failure when changes conflict
- Rebase not needed when session is already up-to-date

## Sample usage

TBD

Reviewed By: srikrishnagopu

Differential Revision: D95099578

Pulled By: joseph5wu

fbshipit-source-id: b665afa35a43829981ce9dd8434abf5b3942882a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants