Skip to content

Commit

Permalink
Move RollingUpdateOnReady to stable
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeffwan committed Sep 28, 2021
1 parent b77874b commit f5558c8
Show file tree
Hide file tree
Showing 7 changed files with 9 additions and 86 deletions.
2 changes: 1 addition & 1 deletion cloudbuild.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ steps:
#

- name: 'e2e-runner'
args: ['PlayerTracking=true&SDKWatchSendOnExecute=false&RollingUpdateOnReady=false&NodeExternalDNS=true&StateAllocationFilter=true&PlayerAllocationFilter=true&CustomFasSyncInterval=true', 'e2e-test-cluster']
args: ['PlayerTracking=true&SDKWatchSendOnExecute=false&NodeExternalDNS=true&StateAllocationFilter=true&PlayerAllocationFilter=true&CustomFasSyncInterval=true', 'e2e-test-cluster']
id: e2e-feature-gates
waitFor:
- push-images
Expand Down
52 changes: 1 addition & 51 deletions pkg/fleets/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -603,57 +603,7 @@ func (c *Controller) rollingUpdateRestFixedOnReady(ctx context.Context, fleet *a

// rollingUpdateRest applies the rolling update to the inactive GameServerSets
func (c *Controller) rollingUpdateRest(ctx context.Context, fleet *agonesv1.Fleet, active *agonesv1.GameServerSet, rest []*agonesv1.GameServerSet) error {
if runtime.FeatureEnabled(runtime.FeatureRollingUpdateOnReady) {
return c.rollingUpdateRestFixedOnReady(ctx, fleet, active, rest)
}
return c.rollingUpdateRestBeforeFixOnReady(ctx, fleet, rest)
}

func (c *Controller) rollingUpdateRestBeforeFixOnReady(ctx context.Context, fleet *agonesv1.Fleet, rest []*agonesv1.GameServerSet) error {
if len(rest) == 0 {
return nil
}

r, err := intstr.GetValueFromIntOrPercent(fleet.Spec.Strategy.RollingUpdate.MaxUnavailable, int(fleet.Spec.Replicas), true)

if err != nil {
return errors.Wrapf(err, "error parsing MaxUnavailable value: %s", fleet.ObjectMeta.Name)
}
unavailable := int32(r)

for _, gsSet := range rest {

// if the status.Replicas are less than or equal to 0, then that means we are done
// scaling this GameServerSet down, and can therefore exit/move to the next one.
if gsSet.Status.Replicas <= 0 {
continue
}

// If the Spec.Replicas does not equal the Status.Replicas for this GameServerSet, this means
// that the rolling down process is currently ongoing, and we should therefore exit so we can wait for it to finish
if gsSet.Spec.Replicas != gsSet.Status.Replicas {
break
}
gsSetCopy := gsSet.DeepCopy()
newReplicasCount := fleet.LowerBoundReplicas(gsSetCopy.Spec.Replicas - unavailable)
if gsSet.Status.ShutdownReplicas == 0 {
gsSetCopy.Spec.Replicas = newReplicasCount
c.loggerForFleet(fleet).Debug(fmt.Sprintf("Replicas in a Shutdown state - %d", gsSet.Status.ShutdownReplicas))
c.loggerForFleet(fleet).WithField("gameserverset", gsSet.ObjectMeta.Name).WithField("replicas", gsSetCopy.Spec.Replicas).
Debug("applying rolling update to inactive gameserverset")

if _, err := c.gameServerSetGetter.GameServerSets(gsSetCopy.ObjectMeta.Namespace).Update(ctx, gsSetCopy, metav1.UpdateOptions{}); err != nil {
return errors.Wrapf(err, "error updating gameserverset %s", gsSetCopy.ObjectMeta.Name)
}
c.recorder.Eventf(fleet, corev1.EventTypeNormal, "ScalingGameServerSet",
"Scaling inactive GameServerSet %s from %d to %d", gsSetCopy.ObjectMeta.Name, gsSet.Spec.Replicas, gsSetCopy.Spec.Replicas)

// let's update just one at a time, slightly slower, but a simpler solution that doesn't require us
// to make sure we don't overshoot the amount that is being shutdown at any given point and time
break
}
}
return nil
return c.rollingUpdateRestFixedOnReady(ctx, fleet, active, rest)
}

// updateFleetStatus gets the GameServerSets for this Fleet and then
Expand Down
16 changes: 1 addition & 15 deletions pkg/fleets/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,6 @@ func TestControllerSyncFleet(t *testing.T) {
})

t.Run("gameserverset with different image details", func(t *testing.T) {
utilruntime.FeatureTestMutex.Lock()
defer utilruntime.FeatureTestMutex.Unlock()
assert.NoError(t, utilruntime.ParseFeatures(string(utilruntime.FeatureRollingUpdateOnReady)+"=true"))

f := defaultFixture()
f.Spec.Strategy.Type = appsv1.RollingUpdateDeploymentStrategyType
f.Spec.Template.Spec.Ports = []agonesv1.GameServerPort{{HostPort: 5555}}
Expand Down Expand Up @@ -1006,12 +1002,7 @@ func TestControllerRollingUpdateDeploymentGSSUpdateFailedErrExpected(t *testing.
assert.EqualError(t, err, "error updating gameserverset inactive: random-err")
}

func TestFeatureRollingUpdateOnReady(t *testing.T) {
utilruntime.FeatureTestMutex.Lock()
defer utilruntime.FeatureTestMutex.Unlock()

assert.NoError(t, utilruntime.ParseFeatures(string(utilruntime.FeatureRollingUpdateOnReady)+"=true"))

func TestRollingUpdateOnReady(t *testing.T) {
type expected struct {
inactiveSpecReplicas int32
replicas int32
Expand Down Expand Up @@ -1118,11 +1109,6 @@ func TestFeatureRollingUpdateOnReady(t *testing.T) {
func TestControllerRollingUpdateDeployment(t *testing.T) {
t.Parallel()

utilruntime.FeatureTestMutex.Lock()
defer utilruntime.FeatureTestMutex.Unlock()

assert.NoError(t, utilruntime.ParseFeatures(string(utilruntime.FeatureRollingUpdateOnReady)+"=false"))

type expected struct {
inactiveSpecReplicas int32
replicas int32
Expand Down
5 changes: 0 additions & 5 deletions pkg/util/runtime/features.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ const (
// FeatureSDKWatchSendOnExecute is a feature flag to enable/disable immediate game server return after SDK.WatchGameServer is called
FeatureSDKWatchSendOnExecute Feature = "SDKWatchSendOnExecute"

// FeatureRollingUpdateOnReady is a feature flag to enable/disable rolling update fix of scale down, when ReadyReplicas
// count is taken into account
FeatureRollingUpdateOnReady Feature = "RollingUpdateOnReady"

// NodeExternalDNS is a feature flag to enable/disable node ExternalDNS and InternalDNS use as GameServer address
NodeExternalDNS Feature = "NodeExternalDNS"

Expand All @@ -63,7 +59,6 @@ var (
FeatureExample: true,
FeaturePlayerTracking: false,
FeatureSDKWatchSendOnExecute: true,
FeatureRollingUpdateOnReady: true,
NodeExternalDNS: false,
FeatureStateAllocationFilter: false,
FeaturePlayerAllocationFilter: false,
Expand Down
1 change: 0 additions & 1 deletion site/content/en/docs/Guides/feature-stages.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ The current set of `alpha` and `beta` feature gates are:
| Example Gate (not in use) | `Example` | Disabled | None | 0.13.0 |
| [Player Tracking]({{< ref "/docs/Guides/player-tracking.md" >}}) | `PlayerTracking` | Disabled | `Alpha` | 1.6.0 |
| [SDK Send GameServer on Watch execution]({{< ref "/docs/Guides/Client SDKs/_index.md#watchgameserverfunctiongameserver" >}}) | `SDKWatchSendOnExecute` | Enabled | `Beta` | 1.12.0 |
| Fix for RollingUpdate [Scale down](https://github.com/googleforgames/agones/issues/1625) | `RollingUpdateOnReady` | Enabled | `Beta` | 1.14.0 |
| [Utilize Node ExternalDNS](https://github.com/googleforgames/agones/issues/1921) and additional [details]({{< ref "/docs/FAQ/_index.md" >}}) | `NodeExternalDNS` | Disabled | `Alpha` | 1.12.0 |
| [Custom resync period for FleetAutoscaler](https://github.com/googleforgames/agones/issues/1955) | `CustomFasSyncInterval` | Disabled | `Alpha` | 1.17.0 |
| [GameServer state filtering on GameServerAllocations](https://github.com/googleforgames/agones/issues/1239) | `StateAllocationFilter` | Disabled | `Alpha` | 1.14.0 |
Expand Down
1 change: 1 addition & 0 deletions site/content/en/docs/Guides/fleet-updates.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ So when a Fleet is edited (any field other than `replicas`, see note below), eit
By default, a Fleet will wait for new `GameSevers` to become `Ready` during a Rolling Update before continuing to shutdown additional `GameServers`, only counting `GameServers` that are `Ready` as being available when calculating the current `maxUnavailable` value which controls the rate at which `GameServers` are updated.
This ensures that a Fleet cannot accidentally have zero `GameServers` in the `Ready` state if something goes wrong during a Rolling Update or if `GameServers` have a long delay before moving to the `Ready` state.

update?
{{< beta title="Rolling Update on Ready" gate="RollingUpdateOnReady" >}}

{{< alert title="Note" color="info">}}
Expand Down
18 changes: 5 additions & 13 deletions test/e2e/fleet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,20 +297,15 @@ func TestFleetRollingUpdate(t *testing.T) {
maxSurge, err := intstr.GetValueFromIntOrPercent(flt.Spec.Strategy.RollingUpdate.MaxSurge, int(flt.Spec.Replicas), true)
assert.Nil(t, err)

roundUp := true
if runtime.FeatureEnabled(runtime.FeatureRollingUpdateOnReady) {
roundUp = false
}
roundUp := false
maxUnavailable, err := intstr.GetValueFromIntOrPercent(flt.Spec.Strategy.RollingUpdate.MaxUnavailable, int(flt.Spec.Replicas), roundUp)

shift := 0
if runtime.FeatureEnabled(runtime.FeatureRollingUpdateOnReady) {
if maxUnavailable == 0 {
maxUnavailable = 1
}
// This difference is inevitable, also could be seen with Deployments and ReplicaSets
shift = maxUnavailable
if maxUnavailable == 0 {
maxUnavailable = 1
}
// This difference is inevitable, also could be seen with Deployments and ReplicaSets
shift = maxUnavailable
assert.Nil(t, err)

expectedTotal := targetScale + maxSurge + maxUnavailable + shift
Expand Down Expand Up @@ -349,9 +344,6 @@ func TestFleetRollingUpdate(t *testing.T) {
}

func TestUpdateFleetReplicaAndSpec(t *testing.T) {
if !runtime.FeatureEnabled(runtime.FeatureRollingUpdateOnReady) {
t.SkipNow()
}
t.Parallel()

client := framework.AgonesClient.AgonesV1()
Expand Down

0 comments on commit f5558c8

Please sign in to comment.