summaryrefslogtreecommitdiff
path: root/jstests/noPassthrough/server_parameter_fcv_upgrade_downgrade.js
blob: c1fef519d4acdbf02c42619e33f18a4329b57da1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
// Test server parameter behavior upon FCV downgrade/upgrade.

(function() {
'use strict';

load("jstests/libs/feature_flag_util.js");

function assertParamExistenceInGetParamStar(output, param, expected) {
    if (output.hasOwnProperty('clusterParameters')) {
        const findRes = output.clusterParameters.find(cp => cp._id === param);
        if (expected) {
            assert.eq(findRes._id, param);
        } else {
            assert.eq(findRes, undefined);
        }
    } else {
        assert.eq(param in output, expected);
    }
}

function runDowngradeUpgradeTestForSP(conn, isMongod) {
    for (let sp of ['spTestNeedsLatestFCV', 'spTestNeedsFeatureFlagBlender']) {
        function assertGetFailed(cmd) {
            const err = assert.commandFailed(cmd).errmsg;
            assert.eq(err, 'no option found to get');
        }
        function assertSetFailed(cmd) {
            const err = assert.commandFailed(cmd).errmsg;
            assert.eq(err, "Server parameter: '" + sp + "' is disabled");
        }

        const admin = conn.getDB('admin');
        const initial = assert.commandWorked(admin.runCommand({getParameter: 1, [sp]: 1}));

        const updateVal = initial[sp] + 1;
        const secondUpdateVal = updateVal + 1;
        assert.commandWorked(admin.runCommand({setParameter: 1, [sp]: updateVal}));

        const changed = assert.commandWorked(admin.runCommand({getParameter: 1, [sp]: 1}));
        assert.eq(changed[sp], updateVal);
        assertParamExistenceInGetParamStar(
            assert.commandWorked(admin.runCommand({getParameter: "*"})), sp, true);

        // Downgrade FCV and ensure we can't get or set if the server knows the FCV (i.e. not
        // mongos)
        assert.commandWorked(admin.runCommand({setFeatureCompatibilityVersion: lastLTSFCV}));
        if (isMongod) {
            assertGetFailed(admin.runCommand({getParameter: 1, [sp]: 1}));
            assertSetFailed(admin.runCommand({setParameter: 1, [sp]: secondUpdateVal}));
        }
        assertParamExistenceInGetParamStar(
            assert.commandWorked(admin.runCommand({getParameter: "*"})), sp, !isMongod);

        // Upgrade FCV and ensure get and set work, and that the value is NOT reset to default, as
        // this is a non-cluster parameter
        assert.commandWorked(admin.runCommand({setFeatureCompatibilityVersion: latestFCV}));
        const afterUpgrade = assert.commandWorked(admin.runCommand({getParameter: 1, [sp]: 1}));
        assert.eq(afterUpgrade[sp], updateVal);

        assert.commandWorked(admin.runCommand({setParameter: 1, [sp]: secondUpdateVal}));

        const changedAgain = assert.commandWorked(admin.runCommand({getParameter: 1, [sp]: 1}));
        assert.eq(changedAgain[sp], secondUpdateVal);

        assertParamExistenceInGetParamStar(
            assert.commandWorked(admin.runCommand({getParameter: "*"})), sp, true);
    }
}

function runDowngradeUpgradeTestForCWSP(conn, isMongod, isStandalone, verifyStateCallback) {
    for (let sp of ['cwspTestNeedsLatestFCV', 'cwspTestNeedsFeatureFlagBlender']) {
        const admin = conn.getDB('admin');

        function assertGetFailed(cmd) {
            const err = assert.commandFailed(cmd).errmsg;
            if (isStandalone && !FeatureFlagUtil.isEnabled(admin, 'AuditConfigClusterParameter')) {
                // In this case, we fail earlier with a different error at the command level.
                assert.eq(err, "getClusterParameter cannot be run on standalones");
            } else {
                assert.eq(err, "Server parameter: '" + sp + "' is disabled");
            }
        }

        function assertSetFailed(cmd) {
            const err = assert.commandFailed(cmd).errmsg;
            if (isStandalone && !FeatureFlagUtil.isEnabled(admin, 'AuditConfigClusterParameter')) {
                // In this case, we fail earlier with a different error at the command level.
                assert.eq(err, "setClusterParameter cannot be run on standalones");
            } else {
                assert.eq(err, "Server parameter: '" + sp + "' is disabled");
            }
        }

        function val(res) {
            const obj = res.clusterParameters.filter((cwsp) => cwsp._id === sp)[0];
            // Default value for CWSPIntStorage is 0
            return (obj === undefined) ? 0 : obj.intData;
        }

        const initial = assert.commandWorked(admin.runCommand({getClusterParameter: sp}));
        const initval = val(initial);

        const updateVal = initval + 1;
        assert.commandWorked(admin.runCommand({setClusterParameter: {[sp]: {intData: updateVal}}}));

        const changed = assert.commandWorked(admin.runCommand({getClusterParameter: sp}));
        assert.eq(val(changed), updateVal);
        assertParamExistenceInGetParamStar(
            assert.commandWorked(admin.runCommand({getClusterParameter: "*"})), sp, true);
        if (verifyStateCallback !== undefined) {
            verifyStateCallback(sp, true);
        }

        // Downgrade FCV and ensure we can't set or get.
        // If our downgrade takes us below the minimum FCV for
        // featureFlagAuditConfigClusterParameter, we expect all cluster parameter commands to fail
        // for standalone.
        assert.commandWorked(admin.runCommand({setFeatureCompatibilityVersion: lastLTSFCV}));

        assertGetFailed(admin.runCommand({getClusterParameter: sp}));
        assertSetFailed(admin.runCommand({setClusterParameter: {[sp]: {intData: updateVal + 1}}}));

        if (!(isStandalone && !FeatureFlagUtil.isEnabled(admin, 'AuditConfigClusterParameter'))) {
            assertParamExistenceInGetParamStar(
                assert.commandWorked(admin.runCommand({getClusterParameter: "*"})), sp, false);
        }
        if (verifyStateCallback !== undefined) {
            verifyStateCallback(sp, false);
        }

        // Upgrade FCV and ensure get and set work, and that the value is reset to default
        assert.commandWorked(admin.runCommand({setFeatureCompatibilityVersion: latestFCV}));
        const afterUpgrade = assert.commandWorked(admin.runCommand({getClusterParameter: sp}));
        assert.eq(val(afterUpgrade), initval);

        assert.commandWorked(admin.runCommand({setClusterParameter: {[sp]: {intData: updateVal}}}));

        const changedAgain = assert.commandWorked(admin.runCommand({getClusterParameter: sp}));
        assert.eq(val(changedAgain), updateVal);

        assertParamExistenceInGetParamStar(
            assert.commandWorked(admin.runCommand({getClusterParameter: "*"})), sp, true);
    }
}

{
    jsTest.log('START standalone');
    const standalone = MongoRunner.runMongod({setParameter: {featureFlagBlender: true}});
    runDowngradeUpgradeTestForSP(standalone, true /* isMongod */);
    if (FeatureFlagUtil.isEnabled(standalone.getDB('admin'), 'AuditConfigClusterParameter')) {
        // This feature flag enables standalone cluster parameters.
        runDowngradeUpgradeTestForCWSP(standalone, true /* isMongod */, true /* isStandalone */);
    }
    MongoRunner.stopMongod(standalone);
    jsTest.log('END standalone');
}

{
    jsTest.log('START replset');
    const rst =
        new ReplSetTest({nodes: 3, nodeOptions: {setParameter: {featureFlagBlender: true}}});
    rst.startSet();
    rst.initiate();
    runDowngradeUpgradeTestForSP(rst.getPrimary(), true /* isMongod */);
    runDowngradeUpgradeTestForCWSP(rst.getPrimary(), true /* isMongod */, false /* isStandalone */);
    rst.stopSet();
    jsTest.log('END replset');
}

{
    jsTest.log('START sharding');
    const options = {setParameter: {featureFlagBlender: true}};
    const s = new ShardingTest({
        mongos: 1,
        config: 1,
        shards: 3,
        mongosOptions: options,
        configOptions: options,
        shardOptions: options
    });
    function verifyParameterState(sp, expectExists) {
        for (let node of [s.configRS.getPrimary(), s.rs0.getPrimary()]) {
            const out = assert.commandWorked(node.adminCommand({getClusterParameter: "*"}));
            assertParamExistenceInGetParamStar(out, sp, expectExists);

            const cpColl = node.getDB('config').clusterParameters;
            assert.eq(cpColl.find({"_id": sp}).itcount(), expectExists ? 1 : 0);
        }
    }
    // mongos is unaware of FCV
    runDowngradeUpgradeTestForSP(s.s0, false /* isMongod */);
    runDowngradeUpgradeTestForCWSP(
        s.s0, false /* isMongod */, false /* isStandalone */, verifyParameterState);
    s.stop();
    jsTest.log('END sharding');
}
})();