Skip to content

Commit 00c3ea3

Browse files
authored
Network: Get fresh copy of global config when retrying network startup (#14540)
This way a fresh copy of state can be retrieved on each iteration when trying to start networks that couldn't be started on the first pass. This helps in scenarios where the network couldn't be started due to a problem with the server/cluster's global config that is rectified and then the go routine running the retry mechanism needs to get an updated copy of the global config before retrying starting the network. Reorganises this function so that the scope of the initial setup attempt's state variable is limited.
2 parents 5159972 + 22d227f commit 00c3ea3

File tree

3 files changed

+62
-62
lines changed

3 files changed

+62
-62
lines changed

lxd/api_cluster.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ func clusterPutBootstrap(d *Daemon, r *http.Request, req api.ClusterPut) respons
423423
}
424424

425425
// Restart the networks (to pickup forkdns and the like).
426-
err = networkStartup(s)
426+
err = networkStartup(d.State)
427427
if err != nil {
428428
return err
429429
}
@@ -849,7 +849,7 @@ func clusterPutJoin(d *Daemon, r *http.Request, req api.ClusterPut) response.Res
849849

850850
// Start up networks so any post-join changes can be applied now that we have a Node ID.
851851
logger.Debug("Starting networks after cluster join")
852-
err = networkStartup(s)
852+
err = networkStartup(d.State)
853853
if err != nil {
854854
logger.Errorf("Failed starting networks: %v", err)
855855
}
@@ -3471,7 +3471,7 @@ func restoreClusterMember(d *Daemon, r *http.Request) response.Response {
34713471
metadata := make(map[string]any)
34723472

34733473
// Restart the networks.
3474-
err = networkStartup(d.State())
3474+
err = networkStartup(d.State)
34753475
if err != nil {
34763476
return err
34773477
}

lxd/daemon.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1653,7 +1653,7 @@ func (d *Daemon) init() error {
16531653
if !d.db.Cluster.LocalNodeIsEvacuated() {
16541654
logger.Infof("Initializing networks")
16551655

1656-
err = networkStartup(d.State())
1656+
err = networkStartup(d.State)
16571657
if err != nil {
16581658
return err
16591659
}

lxd/networks.go

Lines changed: 58 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1548,20 +1548,9 @@ func networkLeasesGet(d *Daemon, r *http.Request) response.Response {
15481548
return response.SyncResponse(true, leases)
15491549
}
15501550

1551-
func networkStartup(s *state.State) error {
1551+
func networkStartup(stateFunc func() *state.State) error {
15521552
var err error
15531553

1554-
// Get a list of projects.
1555-
var projectNames []string
1556-
1557-
err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error {
1558-
projectNames, err = dbCluster.GetProjectNames(ctx, tx.Tx())
1559-
return err
1560-
})
1561-
if err != nil {
1562-
return fmt.Errorf("Failed to load projects: %w", err)
1563-
}
1564-
15651554
// Build a list of networks to initialise, keyed by project and network name.
15661555
const networkPriorityStandalone = 0 // Start networks not dependent on any other network first.
15671556
const networkPriorityPhysical = 1 // Start networks dependent on physical interfaces second.
@@ -1572,38 +1561,14 @@ func networkStartup(s *state.State) error {
15721561
networkPriorityLogical: make(map[network.ProjectNetwork]struct{}),
15731562
}
15741563

1575-
err = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error {
1576-
for _, projectName := range projectNames {
1577-
networkNames, err := tx.GetCreatedNetworkNamesByProject(ctx, projectName)
1578-
if err != nil {
1579-
return fmt.Errorf("Failed to load networks for project %q: %w", projectName, err)
1580-
}
1581-
1582-
for _, networkName := range networkNames {
1583-
pn := network.ProjectNetwork{
1584-
ProjectName: projectName,
1585-
NetworkName: networkName,
1586-
}
1587-
1588-
// Assume all networks are networkPriorityStandalone initially.
1589-
initNetworks[networkPriorityStandalone][pn] = struct{}{}
1590-
}
1591-
}
1592-
1593-
return nil
1594-
})
1595-
if err != nil {
1596-
return err
1597-
}
1598-
15991564
loadedNetworks := make(map[network.ProjectNetwork]network.Network)
16001565

1601-
initNetwork := func(n network.Network, priority int) error {
1566+
initNetwork := func(s *state.State, n network.Network, priority int) error {
16021567
err = n.Start()
16031568
if err != nil {
16041569
err = fmt.Errorf("Failed starting: %w", err)
16051570

1606-
_ = s.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error {
1571+
_ = s.DB.Cluster.Transaction(context.Background(), func(ctx context.Context, tx *db.ClusterTx) error {
16071572
return tx.UpsertWarningLocalNode(ctx, n.Project(), entity.TypeNetwork, int(n.ID()), warningtype.NetworkUnvailable, err.Error())
16081573
})
16091574

@@ -1625,7 +1590,7 @@ func networkStartup(s *state.State) error {
16251590
return nil
16261591
}
16271592

1628-
loadAndInitNetwork := func(pn network.ProjectNetwork, priority int, firstPass bool) error {
1593+
loadAndInitNetwork := func(s *state.State, pn network.ProjectNetwork, priority int, firstPass bool) error {
16291594
var err error
16301595
var n network.Network
16311596

@@ -1670,39 +1635,78 @@ func networkStartup(s *state.State) error {
16701635
return nil
16711636
}
16721637

1673-
err = initNetwork(n, priority)
1638+
err = initNetwork(s, n, priority)
16741639
if err != nil {
16751640
return err
16761641
}
16771642

16781643
return nil
16791644
}
16801645

1681-
// Try initializing networks in priority order.
1682-
for priority := range initNetworks {
1683-
for pn := range initNetworks[priority] {
1684-
err := loadAndInitNetwork(pn, priority, true)
1646+
remainingNetworksCount := func() int {
1647+
remainingNetworks := 0
1648+
for _, projectNetworks := range initNetworks {
1649+
remainingNetworks += len(projectNetworks)
1650+
}
1651+
1652+
return remainingNetworks
1653+
}
1654+
1655+
{
1656+
// Peform first pass to start networks.
1657+
// Local scope for state variable during initial pass of setting up networks.
1658+
s := stateFunc()
1659+
err = s.DB.Cluster.Transaction(s.ShutdownCtx, func(ctx context.Context, tx *db.ClusterTx) error {
1660+
projectNames, err := dbCluster.GetProjectNames(ctx, tx.Tx())
16851661
if err != nil {
1686-
logger.Error("Failed initializing network", logger.Ctx{"project": pn.ProjectName, "network": pn.NetworkName, "err": err})
1662+
return fmt.Errorf("Failed to load projects: %w", err)
1663+
}
16871664

1688-
continue
1665+
for _, projectName := range projectNames {
1666+
networkNames, err := tx.GetCreatedNetworkNamesByProject(ctx, projectName)
1667+
if err != nil {
1668+
return fmt.Errorf("Failed to load networks for project %q: %w", projectName, err)
1669+
}
1670+
1671+
for _, networkName := range networkNames {
1672+
pn := network.ProjectNetwork{
1673+
ProjectName: projectName,
1674+
NetworkName: networkName,
1675+
}
1676+
1677+
// Assume all networks are networkPriorityStandalone initially.
1678+
initNetworks[networkPriorityStandalone][pn] = struct{}{}
1679+
}
16891680
}
1681+
1682+
return nil
1683+
})
1684+
if err != nil {
1685+
return err
16901686
}
1691-
}
16921687

1693-
loadedNetworks = nil // Don't store loaded networks after first pass.
1688+
// Try initializing networks in priority order.
1689+
for priority := range initNetworks {
1690+
for pn := range initNetworks[priority] {
1691+
err := loadAndInitNetwork(s, pn, priority, true)
1692+
if err != nil {
1693+
logger.Error("Failed initializing network", logger.Ctx{"project": pn.ProjectName, "network": pn.NetworkName, "err": err})
16941694

1695-
remainingNetworks := 0
1696-
for _, networks := range initNetworks {
1697-
remainingNetworks += len(networks)
1695+
continue
1696+
}
1697+
}
1698+
}
1699+
1700+
loadedNetworks = nil // Don't store loaded networks after first pass.
16981701
}
16991702

17001703
// For any remaining networks that were not successfully initialised, we now start a go routine to
17011704
// periodically try to initialize them again in the background.
1702-
if remainingNetworks > 0 {
1705+
if remainingNetworksCount() > 0 {
17031706
go func() {
17041707
for {
17051708
t := time.NewTimer(time.Duration(time.Minute))
1709+
s := stateFunc() // Get fresh state in case global config has been updated.
17061710

17071711
select {
17081712
case <-s.ShutdownCtx.Done():
@@ -1716,7 +1720,7 @@ func networkStartup(s *state.State) error {
17161720
// Try initializing networks in priority order.
17171721
for priority := range initNetworks {
17181722
for pn := range initNetworks[priority] {
1719-
err := loadAndInitNetwork(pn, priority, false)
1723+
err := loadAndInitNetwork(s, pn, priority, false)
17201724
if err != nil {
17211725
logger.Error("Failed initializing network", logger.Ctx{"project": pn.ProjectName, "network": pn.NetworkName, "err": err})
17221726

@@ -1727,11 +1731,7 @@ func networkStartup(s *state.State) error {
17271731
}
17281732
}
17291733

1730-
remainingNetworks := 0
1731-
for _, networks := range initNetworks {
1732-
remainingNetworks += len(networks)
1733-
}
1734-
1734+
remainingNetworks := remainingNetworksCount()
17351735
if remainingNetworks <= 0 {
17361736
logger.Info("All networks initialized")
17371737
}

0 commit comments

Comments
 (0)