newHeaders = new HashMap<>(headers);
168 | // Iterate over all keys to find all case combinations
169 | newHeaders.keySet().forEach(key -> {
170 | if (key != null && key.equalsIgnoreCase("Authorization")) {
171 | newHeaders.put(key, "***");
172 | }
173 | });
174 | return newHeaders;
175 | }
176 |
177 | private Utils() {}
178 | }
179 |
--------------------------------------------------------------------------------
/src/main/java/org/jgroups/protocols/kubernetes/pem/Asn1Object.java:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | * Copyright (c) 1998-2009 AOL LLC.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | ****************************************************************************/
17 | package org.jgroups.protocols.kubernetes.pem;
18 |
19 | import java.io.IOException;
20 | import java.math.BigInteger;
21 |
22 | /**
23 | * An ASN.1 TLV. The object is not parsed. It can
24 | * only handle integers and strings.
25 | *
26 | * @author zhang
27 | *
28 | */
29 | class Asn1Object {
30 |
31 | protected final int type;
32 | protected final int length;
33 | protected final byte[] value;
34 | protected final int tag;
35 |
36 | /**
37 | * Construct a ASN.1 TLV. The TLV could be either a
38 | * constructed or primitive entity.
39 | *
40 | * The first byte in DER encoding is made of following fields,
41 | *
42 | *-------------------------------------------------
43 | *|Bit 8|Bit 7|Bit 6|Bit 5|Bit 4|Bit 3|Bit 2|Bit 1|
44 | *-------------------------------------------------
45 | *| Class | CF | + Type |
46 | *-------------------------------------------------
47 | *
48 | *
49 | * - Class: Universal, Application, Context or Private
50 | *
- CF: Constructed flag. If 1, the field is constructed.
51 | *
- Type: This is actually called tag in ASN.1. It
52 | * indicates data type (Integer, String) or a construct
53 | * (sequence, choice, set).
54 | *
55 | *
56 | * @param tag Tag or Identifier
57 | * @param length Length of the field
58 | * @param value Encoded octet string for the field.
59 | */
60 | public Asn1Object(int tag, int length, byte[] value) {
61 | this.tag = tag;
62 | this.type = tag & 0x1F;
63 | this.length = length;
64 | this.value = value;
65 | }
66 |
67 | public int getType() {
68 | return type;
69 | }
70 |
71 | public int getLength() {
72 | return length;
73 | }
74 |
75 | public byte[] getValue() {
76 | return value;
77 | }
78 |
79 | public boolean isConstructed() {
80 | return (tag & DerParser.CONSTRUCTED) == DerParser.CONSTRUCTED;
81 | }
82 |
83 | /**
84 | * For constructed field, return a parser for its content.
85 | *
86 | * @return A parser for the construct.
87 | * @throws IOException
88 | */
89 | public DerParser getParser() throws IOException {
90 | if (!isConstructed())
91 | throw new IOException("Invalid DER: can't parse primitive entity"); //$NON-NLS-1$
92 |
93 | return new DerParser(value);
94 | }
95 |
96 | /**
97 | * Get the value as integer
98 | *
99 | * @return BigInteger
100 | * @throws IOException
101 | */
102 | public BigInteger getInteger() throws IOException {
103 | if (type != DerParser.INTEGER)
104 | throw new IOException("Invalid DER: object is not integer"); //$NON-NLS-1$
105 |
106 | return new BigInteger(value);
107 | }
108 |
109 | /**
110 | * Get value as string. Most strings are treated
111 | * as Latin-1.
112 | *
113 | * @return Java string
114 | * @throws IOException
115 | */
116 | public String getString() throws IOException {
117 |
118 | String encoding;
119 |
120 | switch (type) {
121 |
122 | // Not all are Latin-1 but it's the closest thing
123 | case DerParser.NUMERIC_STRING:
124 | case DerParser.PRINTABLE_STRING:
125 | case DerParser.VIDEOTEX_STRING:
126 | case DerParser.IA5_STRING:
127 | case DerParser.GRAPHIC_STRING:
128 | case DerParser.ISO646_STRING:
129 | case DerParser.GENERAL_STRING:
130 | encoding = "ISO-8859-1"; //$NON-NLS-1$
131 | break;
132 |
133 | case DerParser.BMP_STRING:
134 | encoding = "UTF-16BE"; //$NON-NLS-1$
135 | break;
136 |
137 | case DerParser.UTF8_STRING:
138 | encoding = "UTF-8"; //$NON-NLS-1$
139 | break;
140 |
141 | case DerParser.UNIVERSAL_STRING:
142 | throw new IOException("Invalid DER: can't handle UCS-4 string"); //$NON-NLS-1$
143 |
144 | default:
145 | throw new IOException("Invalid DER: object is not a string"); //$NON-NLS-1$
146 | }
147 |
148 | return new String(value, encoding);
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/src/main/java/org/jgroups/protocols/kubernetes/pem/DerParser.java:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | * Copyright (c) 1998-2009 AOL LLC.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | ****************************************************************************/
17 | package org.jgroups.protocols.kubernetes.pem;
18 |
19 | import java.io.ByteArrayInputStream;
20 | import java.io.IOException;
21 | import java.io.InputStream;
22 | import java.math.BigInteger;
23 |
24 | /**
25 | * A bare-minimum ASN.1 DER decoder, just having enough functions to
26 | * decode PKCS#1 private keys. Especially, it doesn't handle explicitly
27 | * tagged types with an outer tag.
28 | *
29 | * This parser can only handle one layer. To parse nested constructs,
30 | * get a new parser for each layer using Asn1Object.getParser()
.
31 | *
32 | * There are many DER decoders in JRE but using them will tie this
33 | * program to a specific JCE/JVM.
34 | *
35 | * @author zhang
36 | *
37 | */
38 | class DerParser {
39 |
40 | // Classes
41 | public final static int UNIVERSAL = 0x00;
42 | public final static int APPLICATION = 0x40;
43 | public final static int CONTEXT = 0x80;
44 | public final static int PRIVATE = 0xC0;
45 |
46 | // Constructed Flag
47 | public final static int CONSTRUCTED = 0x20;
48 |
49 | // Tag and data types
50 | public final static int ANY = 0x00;
51 | public final static int BOOLEAN = 0x01;
52 | public final static int INTEGER = 0x02;
53 | public final static int BIT_STRING = 0x03;
54 | public final static int OCTET_STRING = 0x04;
55 | public final static int NULL = 0x05;
56 | public final static int OBJECT_IDENTIFIER = 0x06;
57 | public final static int REAL = 0x09;
58 | public final static int ENUMERATED = 0x0a;
59 | public final static int RELATIVE_OID = 0x0d;
60 |
61 | public final static int SEQUENCE = 0x10;
62 | public final static int SET = 0x11;
63 |
64 | public final static int NUMERIC_STRING = 0x12;
65 | public final static int PRINTABLE_STRING = 0x13;
66 | public final static int T61_STRING = 0x14;
67 | public final static int VIDEOTEX_STRING = 0x15;
68 | public final static int IA5_STRING = 0x16;
69 | public final static int GRAPHIC_STRING = 0x19;
70 | public final static int ISO646_STRING = 0x1A;
71 | public final static int GENERAL_STRING = 0x1B;
72 |
73 | public final static int UTF8_STRING = 0x0C;
74 | public final static int UNIVERSAL_STRING = 0x1C;
75 | public final static int BMP_STRING = 0x1E;
76 |
77 | public final static int UTC_TIME = 0x17;
78 | public final static int GENERALIZED_TIME = 0x18;
79 |
80 | protected InputStream in;
81 |
82 | /**
83 | * Create a new DER decoder from an input stream.
84 | *
85 | * @param in
86 | * The DER encoded stream
87 | */
88 | public DerParser(InputStream in) throws IOException {
89 | this.in = in;
90 | }
91 |
92 | /**
93 | * Create a new DER decoder from a byte array.
94 | *
95 | * @param The
96 | * encoded bytes
97 | * @throws IOException
98 | */
99 | public DerParser(byte[] bytes) throws IOException {
100 | this(new ByteArrayInputStream(bytes));
101 | }
102 |
103 | /**
104 | * Read next object. If it's constructed, the value holds
105 | * encoded content and it should be parsed by a new
106 | * parser from Asn1Object.getParser
.
107 | *
108 | * @return A object
109 | * @throws IOException
110 | */
111 | public Asn1Object read() throws IOException {
112 | int tag = in.read();
113 |
114 | if (tag == -1)
115 | throw new IOException("Invalid DER: stream too short, missing tag"); //$NON-NLS-1$
116 |
117 | int length = getLength();
118 |
119 | byte[] value = new byte[length];
120 | int n = in.read(value);
121 | if (n < length)
122 | throw new IOException("Invalid DER: stream too short, missing value"); //$NON-NLS-1$
123 |
124 | Asn1Object o = new Asn1Object(tag, length, value);
125 |
126 | return o;
127 | }
128 |
129 | /**
130 | * Decode the length of the field. Can only support length
131 | * encoding up to 4 octets.
132 | *
133 | * In BER/DER encoding, length can be encoded in 2 forms,
134 | *
135 | * - Short form. One octet. Bit 8 has value "0" and bits 7-1
136 | * give the length.
137 | *
- Long form. Two to 127 octets (only 4 is supported here).
138 | * Bit 8 of first octet has value "1" and bits 7-1 give the
139 | * number of additional length octets. Second and following
140 | * octets give the length, base 256, most significant digit first.
141 | *
142 | * @return The length as integer
143 | * @throws IOException
144 | */
145 | private int getLength() throws IOException {
146 |
147 | int i = in.read();
148 | if (i == -1)
149 | throw new IOException("Invalid DER: length missing"); //$NON-NLS-1$
150 |
151 | // A single byte short length
152 | if ((i & ~0x7F) == 0)
153 | return i;
154 |
155 | int num = i & 0x7F;
156 |
157 | // We can't handle length longer than 4 bytes
158 | if ( i >= 0xFF || num > 4)
159 | throw new IOException("Invalid DER: length field too big (" //$NON-NLS-1$
160 | + i + ")"); //$NON-NLS-1$
161 |
162 | byte[] bytes = new byte[num];
163 | int n = in.read(bytes);
164 | if (n < num)
165 | throw new IOException("Invalid DER: length too short"); //$NON-NLS-1$
166 |
167 | return new BigInteger(1, bytes).intValue();
168 | }
169 |
170 | }
171 |
--------------------------------------------------------------------------------
/src/main/java/org/jgroups/protocols/kubernetes/pem/PEMReader.java:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | * Copyright (c) 1998-2009 AOL LLC.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | ****************************************************************************
17 | *
18 | * @author: zhang
19 | * @version: $Revision$
20 | * @created: Apr 24, 2009
21 | *
22 | * Description: A class to decode PEM files
23 | *
24 | ****************************************************************************/
25 | package org.jgroups.protocols.kubernetes.pem;
26 |
27 | import java.io.BufferedReader;
28 | import java.io.ByteArrayInputStream;
29 | import java.io.FileInputStream;
30 | import java.io.IOException;
31 | import java.io.InputStream;
32 | import java.io.InputStreamReader;
33 | import java.util.Base64;
34 |
35 | /**
36 | * This class convert PEM into byte array. The begin marker
37 | * is saved and it can be used to determine the type of the
38 | * PEM file.
39 | *
40 | * @author zhang
41 | */
42 | public class PEMReader {
43 |
44 | // Begin markers for all supported PEM files
45 | public static final String PRIVATE_PKCS1_MARKER =
46 | "-----BEGIN RSA PRIVATE KEY-----";
47 | public static final String PRIVATE_PKCS8_MARKER =
48 | "-----BEGIN PRIVATE KEY-----";
49 | public static final String CERTIFICATE_X509_MARKER =
50 | "-----BEGIN CERTIFICATE-----";
51 | public static final String PUBLIC_X509_MARKER =
52 | "-----BEGIN PUBLIC KEY-----";
53 |
54 | private static final String BEGIN_MARKER = "-----BEGIN ";
55 |
56 | private final InputStream stream;
57 | private byte[] derBytes;
58 | private String beginMarker;
59 |
60 | public PEMReader(InputStream inStream) throws IOException {
61 | stream = inStream;
62 | readFile();
63 | }
64 |
65 | public PEMReader(byte[] buffer) throws IOException {
66 | this(new ByteArrayInputStream(buffer));
67 | }
68 |
69 | public PEMReader(String fileName) throws IOException {
70 | this(new FileInputStream(fileName));
71 | }
72 |
73 | public byte[] getDerBytes() {
74 | return derBytes;
75 | }
76 |
77 | public String getBeginMarker() {
78 | return beginMarker;
79 | }
80 |
81 | /**
82 | * Read the PEM file and save the DER encoded octet
83 | * stream and begin marker.
84 | *
85 | * @throws IOException
86 | */
87 | protected void readFile() throws IOException {
88 |
89 | String line;
90 | try(BufferedReader reader=new BufferedReader(
91 | new InputStreamReader(stream))) {
92 | while((line=reader.readLine()) != null) {
93 | if(line.contains(BEGIN_MARKER)) {
94 | beginMarker=line.trim();
95 | String endMarker=beginMarker.replace("BEGIN", "END");
96 | derBytes=readBytes(reader, endMarker);
97 | return;
98 | }
99 | }
100 | throw new IOException("Invalid PEM file: no begin marker");
101 | }
102 | }
103 |
104 |
105 | /**
106 | * Read the lines between BEGIN and END marker and convert
107 | * the Base64 encoded content into binary byte array.
108 | *
109 | * @return DER encoded octet stream
110 | * @throws IOException
111 | */
112 | private static byte[] readBytes(BufferedReader reader, String endMarker) throws IOException
113 | {
114 | String line = null;
115 | StringBuilder buf = new StringBuilder();
116 |
117 | while ((line = reader.readLine()) != null)
118 | {
119 | if (line.contains(endMarker)) {
120 | return Base64.getDecoder().decode(buf.toString());
121 | }
122 |
123 | buf.append(line.trim());
124 | }
125 |
126 | throw new IOException("Invalid PEM file: No end marker");
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/main/java/org/jgroups/protocols/kubernetes/pem/PKCS1EncodedKeySpec.java:
--------------------------------------------------------------------------------
1 | /****************************************************************************
2 | * Copyright (c) 1998-2009 AOL LLC.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | *
16 | ****************************************************************************
17 | *
18 | * @author: zhang
19 | * @version: $Revision$
20 | * @created: Apr 24, 2009
21 | *
22 | * Description: A KeySpec for PKCS#1 encoded RSA private key
23 | *
24 | ****************************************************************************/
25 | package org.jgroups.protocols.kubernetes.pem;
26 |
27 | import java.io.IOException;
28 | import java.math.BigInteger;
29 | import java.security.spec.RSAPrivateCrtKeySpec;
30 |
31 | /**
32 | * PKCS#1 encoded private key is commonly used with OpenSSL. It provides CRT parameters
33 | * so the private key operation can be much faster than using exponent/modulus alone,
34 | * which is the case for PKCS#8 encoded key.
35 | *
36 | * Unfortunately, JCE doesn't have an API to decode the DER. This class takes DER
37 | * buffer and decoded into CRT key.
38 | *
39 | * @author zhang
40 | */
41 | public class PKCS1EncodedKeySpec {
42 |
43 | private RSAPrivateCrtKeySpec keySpec;
44 |
45 | /**
46 | * Create a PKCS#1 keyspec from DER encoded buffer
47 | *
48 | * @param keyBytes DER encoded octet stream
49 | * @throws IOException
50 | */
51 | public PKCS1EncodedKeySpec(byte[] keyBytes) throws IOException {
52 | decode(keyBytes);
53 | }
54 |
55 | /**
56 | * Get the key spec that JCE understands.
57 | *
58 | * @return CRT keyspec defined by JCE
59 | */
60 | public RSAPrivateCrtKeySpec getKeySpec() {
61 | return keySpec;
62 | }
63 |
64 | /**
65 | * Decode PKCS#1 encoded private key into RSAPrivateCrtKeySpec.
66 | *
67 | * The ASN.1 syntax for the private key with CRT is
68 | *
69 | *
70 | * --
71 | * -- Representation of RSA private key with information for the CRT algorithm.
72 | * --
73 | * RSAPrivateKey ::= SEQUENCE {
74 | * version Version,
75 | * modulus INTEGER, -- n
76 | * publicExponent INTEGER, -- e
77 | * privateExponent INTEGER, -- d
78 | * prime1 INTEGER, -- p
79 | * prime2 INTEGER, -- q
80 | * exponent1 INTEGER, -- d mod (p-1)
81 | * exponent2 INTEGER, -- d mod (q-1)
82 | * coefficient INTEGER, -- (inverse of q) mod p
83 | * otherPrimeInfos OtherPrimeInfos OPTIONAL
84 | * }
85 | *
86 | *
87 | * @param keyBytes PKCS#1 encoded key
88 | * @throws IOException
89 | */
90 |
91 | private void decode(byte[] keyBytes) throws IOException {
92 |
93 | DerParser parser = new DerParser(keyBytes);
94 |
95 | Asn1Object sequence = parser.read();
96 | if (sequence.getType() != DerParser.SEQUENCE)
97 | throw new IOException("Invalid DER: not a sequence"); //$NON-NLS-1$
98 |
99 | // Parse inside the sequence
100 | parser = sequence.getParser();
101 |
102 | parser.read(); // Skip version
103 | BigInteger modulus = parser.read().getInteger();
104 | BigInteger publicExp = parser.read().getInteger();
105 | BigInteger privateExp = parser.read().getInteger();
106 | BigInteger prime1 = parser.read().getInteger();
107 | BigInteger prime2 = parser.read().getInteger();
108 | BigInteger exp1 = parser.read().getInteger();
109 | BigInteger exp2 = parser.read().getInteger();
110 | BigInteger crtCoef = parser.read().getInteger();
111 |
112 | keySpec = new RSAPrivateCrtKeySpec(
113 | modulus, publicExp, privateExp, prime1, prime2,
114 | exp1, exp2, crtCoef);
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/main/java/org/jgroups/protocols/kubernetes/stream/BaseStreamProvider.java:
--------------------------------------------------------------------------------
1 | package org.jgroups.protocols.kubernetes.stream;
2 |
3 | import org.jgroups.protocols.kubernetes.Utils;
4 |
5 | import java.io.IOException;
6 | import java.net.URL;
7 | import java.net.URLConnection;
8 | import java.util.Map;
9 | import java.util.logging.Level;
10 | import java.util.logging.Logger;
11 |
12 | public abstract class BaseStreamProvider implements StreamProvider {
13 | private static final Logger log = Logger.getLogger(BaseStreamProvider.class.getName());
14 |
15 | public URLConnection openConnection(String url, Map headers, int connectTimeout, int readTimeout) throws IOException {
16 | if (log.isLoggable(Level.FINE)) {
17 | log.log(Level.FINE, String.format("%s opening connection: url [%s], headers [%s], connectTimeout [%s], readTimeout [%s]",
18 | getClass().getSimpleName(), url, Utils.sanitizeHttpHeaders(headers), connectTimeout, readTimeout));
19 | }
20 | URLConnection connection = new URL(url).openConnection();
21 | if (headers != null) {
22 | for (Map.Entry entry : headers.entrySet()) {
23 | connection.addRequestProperty(entry.getKey(), entry.getValue());
24 | }
25 | }
26 | if (connectTimeout < 0 || readTimeout < 0) {
27 | throw new IllegalArgumentException(
28 | String.format("Neither connectTimeout [%s] nor readTimeout [%s] can be less than 0 for URLConnection.", connectTimeout, readTimeout));
29 | }
30 | connection.setConnectTimeout(connectTimeout);
31 | connection.setReadTimeout(readTimeout);
32 | return connection;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/org/jgroups/protocols/kubernetes/stream/CertificateStreamProvider.java:
--------------------------------------------------------------------------------
1 | package org.jgroups.protocols.kubernetes.stream;
2 |
3 | import static org.jgroups.protocols.kubernetes.Utils.openFile;
4 |
5 | import java.io.FileNotFoundException;
6 | import java.io.IOException;
7 | import java.io.InputStream;
8 | import java.net.URLConnection;
9 | import java.security.KeyFactory;
10 | import java.security.KeyStore;
11 | import java.security.cert.Certificate;
12 | import java.security.cert.CertificateFactory;
13 | import java.security.cert.X509Certificate;
14 | import java.security.interfaces.RSAPrivateKey;
15 | import java.security.spec.RSAPrivateCrtKeySpec;
16 | import java.util.Collection;
17 | import java.util.Map;
18 | import java.util.logging.Level;
19 | import java.util.logging.Logger;
20 |
21 | import javax.net.ssl.HttpsURLConnection;
22 | import javax.net.ssl.KeyManager;
23 | import javax.net.ssl.KeyManagerFactory;
24 | import javax.net.ssl.SSLContext;
25 | import javax.net.ssl.SSLSocketFactory;
26 | import javax.net.ssl.TrustManager;
27 | import javax.net.ssl.TrustManagerFactory;
28 |
29 | import org.jgroups.protocols.kubernetes.pem.PEMReader;
30 | import org.jgroups.protocols.kubernetes.pem.PKCS1EncodedKeySpec;
31 |
32 |
33 | /**
34 | * @author From Fabric8
35 | * @author Ales Justin
36 | */
37 | public class CertificateStreamProvider extends BaseStreamProvider {
38 | private static final Logger log = Logger.getLogger(CertificateStreamProvider.class.getName());
39 |
40 | private final SSLSocketFactory factory;
41 |
42 | public CertificateStreamProvider(String clientCertFile, String clientKeyFile, String clientKeyPassword, String clientKeyAlgo, String caCertFile) throws Exception {
43 | // defaults - RSA and empty password
44 | char[] password = (clientKeyPassword != null) ? clientKeyPassword.toCharArray() : new char[0];
45 | String algorithm = (clientKeyAlgo != null) ? clientKeyAlgo : "RSA";
46 |
47 | KeyManager[] keyManagers = configureClientCert(clientCertFile, clientKeyFile, password, algorithm);
48 | TrustManager[] trustManagers = configureCaCert(caCertFile);
49 | SSLContext context = SSLContext.getInstance("TLS");
50 | context.init(keyManagers, trustManagers, null);
51 | factory = context.getSocketFactory();
52 | }
53 |
54 | public InputStream openStream(String url, Map headers, int connectTimeout, int readTimeout) throws IOException {
55 | URLConnection connection = openConnection(url, headers, connectTimeout, readTimeout);
56 | if (connection instanceof HttpsURLConnection) {
57 | HttpsURLConnection httpsConnection = HttpsURLConnection.class.cast(connection);
58 | //httpsConnection.setHostnameVerifier(InsecureStreamProvider.INSECURE_HOSTNAME_VERIFIER);
59 | httpsConnection.setSSLSocketFactory(factory);
60 | if (log.isLoggable(Level.FINE)) {
61 | log.fine(String.format("Using HttpsURLConnection with SSLSocketFactory [%s] for url [%s].", factory, url));
62 | }
63 | } else {
64 | if (log.isLoggable(Level.FINE)) {
65 | log.fine(String.format("Using URLConnection for url [%s].", url));
66 | }
67 | }
68 | return connection.getInputStream();
69 | }
70 |
71 | private static KeyManager[] configureClientCert(String clientCertFile, String clientKeyFile, char[] clientKeyPassword, String clientKeyAlgo) throws Exception {
72 | try {
73 | InputStream certInputStream = openFile(clientCertFile);
74 | CertificateFactory certFactory = CertificateFactory.getInstance("X509");
75 | X509Certificate cert = (X509Certificate)certFactory.generateCertificate(certInputStream);
76 |
77 | InputStream keyInputStream = openFile(clientKeyFile);
78 | PEMReader reader = new PEMReader(keyInputStream);
79 | RSAPrivateCrtKeySpec keySpec = new PKCS1EncodedKeySpec(reader.getDerBytes()).getKeySpec();
80 | KeyFactory kf = KeyFactory.getInstance(clientKeyAlgo);
81 | RSAPrivateKey privKey = (RSAPrivateKey)kf.generatePrivate(keySpec);
82 |
83 | KeyStore keyStore = KeyStore.getInstance("JKS");
84 | keyStore.load(null);
85 |
86 | String alias = cert.getSubjectX500Principal().getName();
87 | keyStore.setKeyEntry(alias, privKey, clientKeyPassword, new Certificate[]{cert});
88 |
89 | KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
90 | keyManagerFactory.init(keyStore, clientKeyPassword);
91 |
92 | return keyManagerFactory.getKeyManagers();
93 | } catch (Exception e) {
94 | log.log(Level.SEVERE, "Could not create key manager for " + clientCertFile + " (" + clientKeyFile + ")", e);
95 | throw e;
96 | }
97 | }
98 |
99 | static TrustManager[] configureCaCert(String caCertFile) throws Exception {
100 | if (caCertFile != null && !caCertFile.isEmpty()) {
101 | try {
102 | InputStream pemInputStream = openFile(caCertFile);
103 | CertificateFactory certFactory = CertificateFactory.getInstance("X509");
104 |
105 | KeyStore trustStore = KeyStore.getInstance("JKS");
106 | trustStore.load(null);
107 |
108 | Collection extends Certificate> certificates = certFactory.generateCertificates(pemInputStream);
109 | for (Certificate c : certificates) {
110 | X509Certificate certificate = (X509Certificate) c;
111 | String alias = certificate.getSubjectX500Principal().getName();
112 | trustStore.setCertificateEntry(alias, certificate);
113 | }
114 |
115 | TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
116 | trustManagerFactory.init(trustStore);
117 |
118 | return trustManagerFactory.getTrustManagers();
119 | } catch (FileNotFoundException ignore) {
120 | log.log(Level.WARNING, "ca cert file not found " + caCertFile + " - defaulting to insecure trust manager");
121 | return TrustManagers.INSECURE_TRUST_MANAGERS;
122 | } catch (Exception e) {
123 | log.log(Level.SEVERE, "Could not create trust manager for " + caCertFile, e);
124 | throw e;
125 | }
126 | } else {
127 | if (log.isLoggable(Level.WARNING)) {
128 | log.log(Level.WARNING, "ca cert file undefined - defaulting to insecure trust manager");
129 | }
130 | return TrustManagers.INSECURE_TRUST_MANAGERS;
131 | }
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/src/main/java/org/jgroups/protocols/kubernetes/stream/DefaultStreamProvider.java:
--------------------------------------------------------------------------------
1 | package org.jgroups.protocols.kubernetes.stream;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.net.URLConnection;
6 | import java.util.Map;
7 | import java.util.logging.Level;
8 | import java.util.logging.Logger;
9 |
10 | public class DefaultStreamProvider extends BaseStreamProvider {
11 | private static final Logger log = Logger.getLogger(DefaultStreamProvider.class.getName());
12 |
13 | public DefaultStreamProvider() {}
14 |
15 | @Override
16 | public InputStream openStream(String url, Map headers, int connectTimeout, int readTimeout) throws IOException {
17 | URLConnection connection = openConnection(url, headers, connectTimeout, readTimeout);
18 | if (log.isLoggable(Level.FINE)) {
19 | log.fine(String.format("Using URLConnection for url [%s].", url));
20 | }
21 | return connection.getInputStream();
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/org/jgroups/protocols/kubernetes/stream/OpenStream.java:
--------------------------------------------------------------------------------
1 | package org.jgroups.protocols.kubernetes.stream;
2 |
3 | import java.io.InputStream;
4 | import java.util.Map;
5 | import java.util.concurrent.Callable;
6 |
7 | public class OpenStream implements Callable {
8 |
9 | private final StreamProvider streamProvider;
10 | private final String url;
11 | private final Map headers;
12 | private final int connectTimeout;
13 | private final int readTimeout;
14 |
15 | public OpenStream(StreamProvider streamProvider, String url, Map headers, int connectTimeout, int readTimeout) {
16 | this.streamProvider = (streamProvider != null) ? streamProvider : new DefaultStreamProvider();
17 | this.url = url;
18 | this.headers = headers;
19 | this.connectTimeout = connectTimeout;
20 | this.readTimeout = readTimeout;
21 | }
22 |
23 | @Override
24 | public InputStream call() throws Exception {
25 | return streamProvider.openStream(url, headers, connectTimeout, readTimeout);
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/org/jgroups/protocols/kubernetes/stream/StreamProvider.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2015 Red Hat, Inc.
3 | *
4 | * Red Hat licenses this file to you under the Apache License, version
5 | * 2.0 (the "License"); you may not use this file except in compliance
6 | * with the License. You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 | * implied. See the License for the specific language governing
14 | * permissions and limitations under the License.
15 | */
16 |
17 | package org.jgroups.protocols.kubernetes.stream;
18 |
19 | import java.io.IOException;
20 | import java.io.InputStream;
21 | import java.util.Map;
22 |
23 |
24 | /**
25 | * @author Kevin Conner
26 | */
27 | public interface StreamProvider {
28 |
29 | InputStream openStream(String url, Map headers, int connectTimeout, int readTimeout) throws IOException;
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/org/jgroups/protocols/kubernetes/stream/TokenStreamProvider.java:
--------------------------------------------------------------------------------
1 | package org.jgroups.protocols.kubernetes.stream;
2 |
3 | import static org.jgroups.protocols.kubernetes.Utils.openFile;
4 |
5 | import javax.net.ssl.HttpsURLConnection;
6 | import javax.net.ssl.SSLContext;
7 | import javax.net.ssl.SSLSocketFactory;
8 | import javax.net.ssl.TrustManager;
9 | import javax.net.ssl.TrustManagerFactory;
10 | import java.io.FileNotFoundException;
11 | import java.io.IOException;
12 | import java.io.InputStream;
13 | import java.net.URLConnection;
14 | import java.security.KeyStore;
15 | import java.security.cert.Certificate;
16 | import java.security.cert.CertificateFactory;
17 | import java.security.cert.X509Certificate;
18 | import java.util.Collection;
19 | import java.util.Map;
20 | import java.util.logging.Level;
21 | import java.util.logging.Logger;
22 |
23 | /**
24 | * Copied and adapted version from openshift-ping repository. A warning message is issued if ca cert file is undefined or not
25 | * found rather than always using insecure stream or being mandatory and eventually failing.
26 | *
27 | * @author Ricardo Martinelli
28 | * @author Radoslav Husar
29 | */
30 | public class TokenStreamProvider extends BaseStreamProvider {
31 |
32 | private static final Logger log = Logger.getLogger(TokenStreamProvider.class.getName());
33 |
34 | private String token;
35 |
36 | private String caCertFile;
37 |
38 | private SSLSocketFactory factory;
39 |
40 | public TokenStreamProvider(String token, String caCertFile) {
41 | this.token = token;
42 | this.caCertFile = caCertFile;
43 | }
44 |
45 | @Override
46 | public InputStream openStream(String url, Map headers, int connectTimeout, int readTimeout)
47 | throws IOException {
48 | URLConnection connection = openConnection(url, headers, connectTimeout, readTimeout);
49 |
50 | if (connection instanceof HttpsURLConnection) {
51 | HttpsURLConnection httpsConnection = HttpsURLConnection.class.cast(connection);
52 | //httpsConnection.setHostnameVerifier(InsecureStreamProvider.INSECURE_HOSTNAME_VERIFIER);
53 | httpsConnection.setSSLSocketFactory(getSSLSocketFactory());
54 | if (log.isLoggable(Level.FINE)) {
55 | log.fine(String.format("Using HttpsURLConnection with SSLSocketFactory [%s] for url [%s].", factory, url));
56 | }
57 | } else {
58 | if (log.isLoggable(Level.FINE)) {
59 | log.fine(String.format("Using URLConnection for url [%s].", url));
60 | }
61 | }
62 |
63 | if (token != null) {
64 | // curl -k -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
65 | // https://172.30.0.2:443/api/v1/namespaces/dward/pods?labelSelector=application%3Deap-app
66 | headers.put("Authorization", "Bearer " + token);
67 | }
68 | return connection.getInputStream();
69 | }
70 |
71 | static TrustManager[] configureCaCert(String caCertFile) throws Exception {
72 | if (caCertFile != null && !caCertFile.isEmpty()) {
73 | try {
74 | InputStream pemInputStream = openFile(caCertFile);
75 | CertificateFactory certFactory = CertificateFactory.getInstance("X509");
76 |
77 | KeyStore trustStore = KeyStore.getInstance("JKS");
78 | trustStore.load(null);
79 |
80 | Collection extends Certificate> certificates = certFactory.generateCertificates(pemInputStream);
81 | for (Certificate c : certificates) {
82 | X509Certificate certificate = (X509Certificate) c;
83 | String alias = certificate.getSubjectX500Principal().getName();
84 | trustStore.setCertificateEntry(alias, certificate);
85 | }
86 |
87 | TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
88 | trustManagerFactory.init(trustStore);
89 |
90 | return trustManagerFactory.getTrustManagers();
91 | } catch (FileNotFoundException ignore) {
92 | log.log(Level.WARNING, "ca cert file not found " + caCertFile + " - defaulting to insecure trust manager");
93 | return TrustManagers.INSECURE_TRUST_MANAGERS;
94 | } catch (Exception e) {
95 | log.log(Level.SEVERE, "Could not create trust manager for " + caCertFile, e);
96 | throw e;
97 | }
98 | } else {
99 | log.log(Level.WARNING, "ca cert file undefined - defaulting to insecure trust manager");
100 | return TrustManagers.INSECURE_TRUST_MANAGERS;
101 | }
102 | }
103 |
104 | private SSLSocketFactory getSSLSocketFactory() throws IOException {
105 | if(this.factory == null) {
106 | synchronized(this) {
107 | if(this.factory == null) {
108 | try {
109 | TrustManager[] trustManagers = configureCaCert(this.caCertFile);
110 | SSLContext context = SSLContext.getInstance("TLS");
111 | context.init(null, trustManagers, null);
112 | this.factory = context.getSocketFactory();
113 | } catch(Exception e) {
114 | throw new IOException(e);
115 | }
116 | }
117 | }
118 | }
119 | return this.factory;
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/src/main/java/org/jgroups/protocols/kubernetes/stream/TrustManagers.java:
--------------------------------------------------------------------------------
1 | package org.jgroups.protocols.kubernetes.stream;
2 |
3 | import javax.net.ssl.TrustManager;
4 | import javax.net.ssl.X509TrustManager;
5 | import java.security.cert.X509Certificate;
6 |
7 | /**
8 | * @author Radoslav Husar
9 | */
10 | enum TrustManagers {
11 | ;
12 |
13 | static final TrustManager[] INSECURE_TRUST_MANAGERS = {
14 | new X509TrustManager() {
15 | @Override
16 | public void checkClientTrusted(X509Certificate[] chain, String authType) {
17 | }
18 |
19 | @Override
20 | public void checkServerTrusted(X509Certificate[] chain, String authType) {
21 | }
22 |
23 | @Override
24 | public X509Certificate[] getAcceptedIssuers() {
25 | return null;
26 | }
27 | }
28 | };
29 | }
30 |
--------------------------------------------------------------------------------
/src/test/java/org/jgroups/ping/kube/test/CertsTest.java:
--------------------------------------------------------------------------------
1 | package org.jgroups.ping.kube.test;
2 |
3 | import org.jgroups.protocols.kubernetes.stream.CertificateStreamProvider;
4 | import org.junit.Test;
5 |
6 | import java.io.InputStream;
7 |
8 | import static org.jgroups.protocols.kubernetes.Utils.getSystemEnv;
9 | import static org.jgroups.protocols.kubernetes.Utils.getSystemProperty;
10 |
11 | /**
12 | * @author Ales Justin
13 | */
14 | public class CertsTest {
15 |
16 | private static String getValue(String name) {
17 | return getValue(name, null);
18 | }
19 |
20 | private static String getValue(String name, String defaultValue) {
21 | String value = getSystemEnv(name);
22 | return value != null ? value : getSystemProperty(name, defaultValue);
23 | }
24 |
25 | @Test
26 | public void testCerts() throws Exception {
27 | String clientCertFile = getValue("KUBERNETES_CLIENT_CERTIFICATE_FILE");
28 | String clientKeyFile = getValue("KUBERNETES_CLIENT_KEY_FILE");
29 | String clientKeyPassword = getValue("KUBERNETES_CLIENT_KEY_PASSWORD");
30 | String clientKeyAlgo = getValue("KUBERNETES_CLIENT_KEY_ALGO");
31 | String caCertFile = getValue("KUBERNETES_CA_CERTIFICATE_FILE");
32 |
33 | if (clientCertFile == null) {
34 | return;
35 | }
36 |
37 | CertificateStreamProvider certStreamProvider =
38 | new CertificateStreamProvider(clientCertFile, clientKeyFile, clientKeyPassword, clientKeyAlgo, caCertFile);
39 |
40 | String k8s_master = getValue("KUBERNETES_MASTER");
41 | String apiVersion = getValue("API_VERSION", "v1beta1");
42 | String op = getValue("OP", "pods");
43 |
44 | try (InputStream is = certStreamProvider.openStream(String.format("%s/api/%s/%s", k8s_master, apiVersion, op), null, 0, 0)) {
45 | int x;
46 | while ((x = is.read()) != -1) {
47 | System.out.print((char) x);
48 | }
49 | }
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/test/java/org/jgroups/ping/kube/test/ClientTest.java:
--------------------------------------------------------------------------------
1 |
2 | package org.jgroups.ping.kube.test;
3 |
4 | import static org.junit.Assert.assertEquals;
5 |
6 | import java.util.List;
7 |
8 | import org.jgroups.protocols.kubernetes.Client;
9 | import org.jgroups.protocols.kubernetes.Pod;
10 | import org.junit.Assert;
11 | import org.junit.Test;
12 |
13 | /**
14 | * @author Ales Justin
15 | */
16 | public class ClientTest {
17 |
18 | @Test
19 | public void testPods() throws Exception {
20 | Client client = new TestClient();
21 | List pods = client.getPods(null, null, false);
22 | Assert.assertNotNull(pods);
23 | assertEquals(2, pods.size());
24 | String pod = pods.get(0).getIp();
25 | Assert.assertNotNull(pod);
26 | }
27 |
28 | @Test
29 | public void testParsingPortWithoutNames() throws Exception {
30 | //given
31 | Client client = new TestClient("/pods_without_ports.json");
32 |
33 | //when
34 | int numberOfPods = client.getPods(null, null, false).size();
35 |
36 | //then
37 | assertEquals(2, numberOfPods);
38 | }
39 |
40 | @Test
41 | public void testParsingPodGroupPodTemplateHash() throws Exception {
42 | //given
43 | Client client = new TestClient("/pods_without_ports.json");
44 |
45 | //when
46 | String podGroup = client.getPods(null, null, false).get(0).getPodGroup();
47 |
48 | //then
49 | assertEquals("infinispan-simple-tutorials-kubernetes-5", podGroup);
50 | }
51 |
52 | @Test
53 | public void testParsingPodGroupOpenshift() throws Exception {
54 | //given
55 | Client client = new TestClient("/replicaset_rolling_update.json");
56 |
57 | //when
58 | String podGroup = client.getPods(null, null, false).get(0).getPodGroup();
59 |
60 | //then
61 | assertEquals("6569c544b", podGroup);
62 | }
63 |
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/test/java/org/jgroups/ping/kube/test/JsonTest.java:
--------------------------------------------------------------------------------
1 | package org.jgroups.ping.kube.test;
2 |
3 | import mjson.Json;
4 | import org.junit.Test;
5 |
6 | import java.io.File;
7 | import java.util.List;
8 |
9 | import static org.jgroups.protocols.kubernetes.Utils.readFileToString;
10 | import static org.junit.Assert.assertEquals;
11 |
12 | /**
13 | * @author Bela Ban
14 | * @since x.y
15 | */
16 | public class JsonTest {
17 |
18 | @Test
19 | public void testJsonParser() throws Exception {
20 | String input=readFileToString(new File(TestClient.class.getResource("/pods_without_ports.json").toURI()));
21 |
22 | Json json=Json.read(input);
23 |
24 | List items=json.at("items").asJsonList();
25 |
26 | for(Json obj: items) {
27 | Json status=obj.at("status");
28 | Json phase=status.at("phase");
29 | Json ip=status.at("podIP");
30 | System.out.printf("%s -> %s\n", ip, phase);
31 | assertEquals("Running", phase.asString());
32 | }
33 |
34 | /* JsonObject root=JsonParser.object().from(input);
35 | JsonArray items=root.getArray("items");
36 |
37 | for(int i=0; i < items.size(); i++) {
38 | JsonObject obj=items.getObject(i);
39 | JsonObject status=obj.getObject("status");
40 | String hostIP=status.getString("hostIP");
41 | System.out.println("hostIP = " + hostIP);
42 | }*/
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/org/jgroups/ping/kube/test/RollingUpdateTest.java:
--------------------------------------------------------------------------------
1 | package org.jgroups.ping.kube.test;
2 |
3 | import org.assertj.core.api.Assertions;
4 | import org.jgroups.JChannel;
5 | import org.jgroups.Message;
6 | import org.jgroups.protocols.TCP;
7 | import org.jgroups.protocols.kubernetes.KUBE_PING;
8 | import org.jgroups.protocols.kubernetes.Pod;
9 | import org.jgroups.protocols.pbcast.GMS;
10 | import org.jgroups.protocols.pbcast.NAKACK2;
11 | import org.jgroups.stack.IpAddress;
12 | import org.junit.Test;
13 |
14 | import java.net.InetAddress;
15 | import java.util.ArrayList;
16 | import java.util.List;
17 | import java.util.Set;
18 | import java.util.stream.Collectors;
19 |
20 | import static org.jgroups.ping.kube.test.util.FreePortFinder.findFreePort;
21 |
22 | /**
23 | * Tests Rolling update scenarios.
24 | *
25 | *
26 | * The idea of this tests is to mock the Kubernetes API response and check which hosts were queried during
27 | * initial discovery. This way we will know which hosts where put into the cluster.
28 | *
29 | */
30 | public class RollingUpdateTest {
31 |
32 | @Test
33 | public void testPuttingAllNodesInTheSameClusterDuringRollingUpdate() throws Exception {
34 | //given
35 | KUBE_PING_FOR_TESTING testedProtocol = new KUBE_PING_FOR_TESTING("/openshift_rolling_update.json");
36 |
37 | //when
38 | sendInitialDiscovery(testedProtocol);
39 | Set membersUsedForDiscovery = testedProtocol.getCollectedMessages().stream()
40 | .map(e -> ((IpAddress)e.getDest()).getIpAddress().getHostAddress())
41 | .collect(Collectors.toSet());
42 | List allPodsFromKubernetesApi = testedProtocol.getPods().stream()
43 | .map(Pod::getIp)
44 | .collect(Collectors.toList());
45 |
46 | //then
47 | Assertions.assertThat(membersUsedForDiscovery).hasSameElementsAs(allPodsFromKubernetesApi);
48 | }
49 |
50 | @Test
51 | public void testPutOnlyNodesWithTheSameParentDuringRollingUpdateOpenShift() throws Exception {
52 | //given
53 | KUBE_PING_FOR_TESTING testedProtocol = new KUBE_PING_FOR_TESTING("/openshift_rolling_update.json");
54 | testedProtocol.setValue("split_clusters_during_rolling_update", true);
55 |
56 | //when //then
57 | testPutOnlyNodesWithTheSameParentDuringRollingUpdate(testedProtocol);
58 | }
59 |
60 | @Test
61 | public void testPutOnlyNodesWithTheSameParentDuringRollingUpdateReplicaSet() throws Exception {
62 | //given
63 | KUBE_PING_FOR_TESTING testedProtocol = new KUBE_PING_FOR_TESTING("/replicaset_rolling_update.json");
64 | testedProtocol.setValue("split_clusters_during_rolling_update", true);
65 |
66 | //when //then
67 | testPutOnlyNodesWithTheSameParentDuringRollingUpdate(testedProtocol);
68 | }
69 |
70 | @Test
71 | public void testPutOnlyNodesWithTheSameParentDuringRollingUpdateStatefulSet() throws Exception {
72 | //given
73 | KUBE_PING_FOR_TESTING testedProtocol = new KUBE_PING_FOR_TESTING("/statefulset_rolling_update.json");
74 | testedProtocol.setValue("split_clusters_during_rolling_update", true);
75 |
76 | //when //then
77 | testPutOnlyNodesWithTheSameParentDuringRollingUpdate(testedProtocol);
78 | }
79 |
80 | private void testPutOnlyNodesWithTheSameParentDuringRollingUpdate(KUBE_PING_FOR_TESTING testedProtocol) throws Exception {
81 | //when
82 | sendInitialDiscovery(testedProtocol);
83 | String senderParentDeployment = testedProtocol.getPods().stream()
84 | .filter(pod -> "127.0.0.1".equals(pod.getIp()))
85 | .map(Pod::getPodGroup)
86 | .findFirst().get();
87 | Set membersUsedForDiscovery = testedProtocol.getCollectedMessages().stream()
88 | .map(e -> ((IpAddress)e.getDest()).getIpAddress().getHostAddress())
89 | .collect(Collectors.toSet());
90 | List allowedPodsFromKubernetesApi = testedProtocol.getPods().stream()
91 | .filter(pod -> senderParentDeployment.equals(pod.getPodGroup()))
92 | .map(Pod::getIp)
93 | .collect(Collectors.toList());
94 |
95 | //then
96 | Assertions.assertThat(allowedPodsFromKubernetesApi).containsAll(membersUsedForDiscovery);
97 | }
98 |
99 | private static void sendInitialDiscovery(KUBE_PING kubePingProtocol) throws Exception {
100 | new JChannel(
101 | new TCP().setValue("bind_addr", InetAddress.getLoopbackAddress()).setValue("bind_port", findFreePort()),
102 | kubePingProtocol,
103 | new NAKACK2(),
104 | new GMS().setValue("join_timeout", 1)
105 | ).connect("RollingUpdateTest").disconnect();
106 | }
107 |
108 | static class KUBE_PING_FOR_TESTING extends KUBE_PING {
109 |
110 | private final String resourceFile;
111 | private final List collectedMessages = new ArrayList<>();
112 | private List pods;
113 |
114 | KUBE_PING_FOR_TESTING(String resourceFile) {
115 | this.resourceFile = resourceFile;
116 | }
117 |
118 | @Override
119 | public void init() throws Exception {
120 | super.init();
121 | client = new TestClient(resourceFile);
122 | pods = client.getPods(namespace, labels, true);
123 | }
124 |
125 | @Override
126 | protected void sendDiscoveryRequest(Message req) {
127 | collectedMessages.add(req);
128 | }
129 |
130 | List getCollectedMessages() {
131 | return collectedMessages;
132 | }
133 |
134 | List getPods() {
135 | return pods;
136 | }
137 | }
138 |
139 | }
140 |
--------------------------------------------------------------------------------
/src/test/java/org/jgroups/ping/kube/test/StatusTest.java:
--------------------------------------------------------------------------------
1 | package org.jgroups.ping.kube.test;
2 |
3 | import java.util.List;
4 |
5 | import org.jgroups.protocols.kubernetes.Client;
6 | import org.jgroups.protocols.kubernetes.Pod;
7 | import org.junit.Assert;
8 | import org.junit.Test;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * @author Ulrich Romahn
14 | */
15 | public class StatusTest {
16 |
17 | @Test
18 | public void testPodsRunning() throws Exception {
19 | Client client = new TestClient("/complex_pods.json");
20 | List pods = client.getPods(null, null, false);
21 | Assert.assertNotNull(pods);
22 | assertEquals(4, pods.size());
23 | String pod = pods.get(0).getIp();
24 | Assert.assertNotNull(pod);
25 | }
26 |
27 | @Test
28 | public void testOnePodNotRunning() throws Exception {
29 | final String jsonFile = "/unknown_pods.json";
30 | Client client = new TestClient(jsonFile);
31 | List pods = client.getPods(null, null, false);
32 | Assert.assertNotNull(pods);
33 | assertEquals(3, pods.size());
34 | assertTrue(pods.get(0).isReady());
35 | assertTrue(pods.get(1).isReady());
36 | assertFalse(pods.get(2).isReady());
37 | String pod = pods.get(0).getIp();
38 | Assert.assertNotNull(pod);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/test/java/org/jgroups/ping/kube/test/TestClient.java:
--------------------------------------------------------------------------------
1 |
2 | package org.jgroups.ping.kube.test;
3 |
4 | import org.jgroups.logging.LogFactory;
5 | import org.jgroups.protocols.kubernetes.Client;
6 |
7 | import java.io.File;
8 | import java.io.IOException;
9 | import java.net.URISyntaxException;
10 | import java.util.HashMap;
11 | import java.util.Map;
12 |
13 | import static org.jgroups.protocols.kubernetes.Utils.readFileToString;
14 |
15 | /**
16 | * @author Ales Justin
17 | */
18 | public class TestClient extends Client {
19 | private final Map OPS = new HashMap<>();
20 |
21 |
22 | public TestClient() throws URISyntaxException, IOException {
23 | this("/pods.json");
24 | }
25 |
26 | public TestClient(String jsonFile) throws URISyntaxException, IOException {
27 | super(null, null, 0, 0, 0, 0,
28 | null, LogFactory.getLog(TestClient.class));
29 | String json = readFileToString(new File(TestClient.class.getResource(jsonFile).toURI()));
30 | OPS.put("pods", json);
31 | }
32 |
33 | @Override
34 | protected String fetchFromKubernetes(String op, String namespace, String labels, boolean dump_requests) throws Exception {
35 | String value = OPS.get(op);
36 | if (value == null)
37 | throw new IllegalStateException("No such op: " + op);
38 | return value;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/test/java/org/jgroups/ping/kube/test/util/FreePortFinder.java:
--------------------------------------------------------------------------------
1 | package org.jgroups.ping.kube.test.util;
2 |
3 | import java.net.ServerSocket;
4 |
5 | public class FreePortFinder {
6 |
7 | private static final int DEFAULT_PORT = 13256;
8 |
9 | private FreePortFinder() { }
10 |
11 | public static int findFreePort() {
12 | try (ServerSocket socket = new ServerSocket(0)) {
13 | return socket.getLocalPort();
14 | } catch (Exception e) {
15 | return DEFAULT_PORT;
16 | }
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/test/java/org/jgroups/protocols/kubernetes/UtilsTest.java:
--------------------------------------------------------------------------------
1 | package org.jgroups.protocols.kubernetes;
2 |
3 | import org.assertj.core.api.Assertions;
4 | import org.junit.Test;
5 |
6 | import java.util.Map;
7 |
8 | public class UtilsTest {
9 |
10 | @Test
11 | public void testSanitizeHttpHeaders() {
12 | Map sanitized = Utils.sanitizeHttpHeaders(Map.of(
13 | "Host", "jgroups.org",
14 | "Authorization", "Basic abcd",
15 | "authorization", "Bearer abcd"
16 | ));
17 | Assertions.assertThat(sanitized.get("Host")).isEqualTo("jgroups.org");
18 | Assertions.assertThat(sanitized.get("Authorization")).isEqualTo("***");
19 | Assertions.assertThat(sanitized.get("authorization")).isEqualTo("***");
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/test/java/org/jgroups/protocols/kubernetes/stream/StreamProviderTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Red Hat, Inc.
3 | *
4 | * Red Hat licenses this file to you under the Apache License, version
5 | * 2.0 (the "License"); you may not use this file except in compliance
6 | * with the License. You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 | * implied. See the License for the specific language governing
14 | * permissions and limitations under the License.
15 | */
16 |
17 | package org.jgroups.protocols.kubernetes.stream;
18 |
19 | import static org.junit.Assert.assertEquals;
20 | import static org.junit.Assert.assertTrue;
21 |
22 | import javax.net.ssl.TrustManager;
23 | import javax.net.ssl.X509TrustManager;
24 | import java.security.cert.X509Certificate;
25 | import java.util.stream.Stream;
26 |
27 | import org.junit.Test;
28 |
29 | /**
30 | * Verify {@link TokenStreamProvider} and {@link CertificateStreamProvider} correctly parse all certificates from the file.
31 | *
32 | * @author Radoslav Husar
33 | */
34 | public class StreamProviderTest {
35 |
36 | private static String CA_FILE = StreamProviderTest.class.getResource("/certificates/ca.crt").getFile();
37 |
38 | @Test
39 | public void testTokenStreamProviderCaCert() throws Exception {
40 | testConfigureCaCert(TokenStreamProvider.configureCaCert(CA_FILE));
41 | }
42 |
43 | @Test
44 | public void testCertificateStreamProviderCaCert() throws Exception {
45 | testConfigureCaCert(CertificateStreamProvider.configureCaCert(CA_FILE));
46 | }
47 |
48 | private static void testConfigureCaCert(TrustManager[] trustManagers) {
49 | assertEquals(1, trustManagers.length);
50 | X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
51 | X509Certificate[] acceptedIssuers = trustManager.getAcceptedIssuers();
52 |
53 | // Assert all 4 CA certs are parsed
54 | assertTrue(Stream.of("CN=kube-apiserver-localhost-signer", "CN=kube-apiserver-service-network-signer", "CN=ingress-operator@1559194394", "CN=kube-apiserver-lb-signer")
55 | .allMatch(cn -> Stream.of(acceptedIssuers)
56 | .anyMatch(c -> c.getSubjectDN().toString().startsWith(cn)))
57 | );
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/test/resources/certificates/ca.crt:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDMjCCAhqgAwIBAgIIcdNISRMjaAowDQYJKoZIhvcNAQELBQAwNzESMBAGA1UE
3 | CxMJb3BlbnNoaWZ0MSEwHwYDVQQDExhrdWJlLWFwaXNlcnZlci1sYi1zaWduZXIw
4 | HhcNMTkwNTMwMDUxMzA0WhcNMjkwNTI3MDUxMzA0WjA3MRIwEAYDVQQLEwlvcGVu
5 | c2hpZnQxITAfBgNVBAMTGGt1YmUtYXBpc2VydmVyLWxiLXNpZ25lcjCCASIwDQYJ
6 | KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMcI/8AJKXcYUuCR+guB0W8pBhMaF1fF
7 | B4sSKz1oyy9IuaXH4FkKNxzmDQoET6gweo19yh07DgtyqQbmQkuUkoTS/cZMV+dZ
8 | GYVhMZOSjXLrddc/DUNZZiMzuQx/d+B0GZ3lfcB8BlMX5BISnWSh/GKkQ6rRwi/B
9 | 3fcLevQc8nrk4QXVLuENaUiJl0e59xmmbfwKDzKywNd8lpJDXcze98uCauuWpfPg
10 | dLt6VXuh9xqbn0N1t3EFuEW/NBFDbc0KcnPT0wMN9iIfqKuRoYVaqTmKQwhrR/H9
11 | CkHx3yfgdvk7ojQa427+Q2XDfxT7H1FFY57Zamvp9PUizNeZK0rf5FECAwEAAaNC
12 | MEAwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIF0
13 | AGiEFKwIF78/RK+m6/A7LlUfMA0GCSqGSIb3DQEBCwUAA4IBAQBwSk/PbBVLRx5C
14 | Y/CHH+tNBzL1de04A789Tp2jqix0CYR6uDkmjEA0wuSxvLzmlo6VfNVhTRJy3Wv6
15 | DCAHWt2tZTi8F7V2q8FWdrVaFMc2z1ciGFkJirbzjBVKIQoRz6M75acGruCy9jsg
16 | me9oI8GfXb5Eej3M0LkKJlkT9urM/x3xfpieibUQ43yUB1Ubs93VqlM9YrggTI2l
17 | 3VhW6NRbHBv+Fmq2l6BUcBwc5p4HRk6TxaKfB0nl20SL0PkgLUuJT9vt4zjkvxfY
18 | q5YKse6Flnn7SPyVa5JDpM1SFHU59I3XIhgg36/+k2jM4GHcOTdgnyXKOSPehDfz
19 | J1sm6h0F
20 | -----END CERTIFICATE-----
21 | -----BEGIN CERTIFICATE-----
22 | MIIDQDCCAiigAwIBAgIIFZBaPRIOJqgwDQYJKoZIhvcNAQELBQAwPjESMBAGA1UE
23 | CxMJb3BlbnNoaWZ0MSgwJgYDVQQDEx9rdWJlLWFwaXNlcnZlci1sb2NhbGhvc3Qt
24 | c2lnbmVyMB4XDTE5MDUzMDA1MTMwM1oXDTI5MDUyNzA1MTMwM1owPjESMBAGA1UE
25 | CxMJb3BlbnNoaWZ0MSgwJgYDVQQDEx9rdWJlLWFwaXNlcnZlci1sb2NhbGhvc3Qt
26 | c2lnbmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3MQaqUapUTSm
27 | s2PNgvyBNtUmjHJDqcAX8keUcGEbxKmP8xrM0Yuj1Vwaynak3jeKVpaLbUnSs8W9
28 | Qyx4FlBJsA7yTc7zx1PzFL5M2TWqPkNCnyV/4uzYAg9uib1a5kmC7VYSc+WQvGjd
29 | LRVQFSEYHrj27pYHQJ8ru+D36MOT51ZZdOpmDAo6967CgDwPfmP3XLV8tJ42qCRM
30 | AmY9087EdyGTrQapcXqW4CcNafdTUCVS/KaPHrwOYdPwYXZvLyAakRD6J+Q29BDx
31 | PbwMwlviItmvdAJSEU5C+OMIRPmiPTWf8cykYK/L0pk40jRsriUiH0WFSChj1Pbw
32 | ZC/xeFPMYwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAqQwDwYDVR0TAQH/BAUwAwEB
33 | /zAdBgNVHQ4EFgQUd3L7fd3tVtMCAuyypfMTP8VBEfAwDQYJKoZIhvcNAQELBQAD
34 | ggEBAChq12ywxoU7WFBmdGHDTzoMhTtXE/xJj7HD4jqvOh7U5pA7WMnI1uR0Aeiv
35 | 8rtdSsO+XWIVeftnD2n9v6MkqwEKWw9bzmKd/XBfcvo7dCsaJpaWlGAW036LyXkM
36 | T9lJDIUIBRBvW39Ua380vGoyDggClU5jzw22I9A9NhrUNCec0z9BI2c6oR8PUZs4
37 | fjIV/zsplcKtYDISprYuq12ntJ1VoDjnQuPDJDfXkY7pd+VChBkRjkVo0afrca2W
38 | HLUU3BMqd/N80Q16Cygpa2vD13TfONuq4YxUEvT+USgTpnQdHeA15YVEHJQwfP/x
39 | uUGIpS8/3k0Swsn3tZ4gstjzkvI=
40 | -----END CERTIFICATE-----
41 | -----BEGIN CERTIFICATE-----
42 | MIIDTDCCAjSgAwIBAgIIT8guxr4pPjAwDQYJKoZIhvcNAQELBQAwRDESMBAGA1UE
43 | CxMJb3BlbnNoaWZ0MS4wLAYDVQQDEyVrdWJlLWFwaXNlcnZlci1zZXJ2aWNlLW5l
44 | dHdvcmstc2lnbmVyMB4XDTE5MDUzMDA1MTMwM1oXDTI5MDUyNzA1MTMwM1owRDES
45 | MBAGA1UECxMJb3BlbnNoaWZ0MS4wLAYDVQQDEyVrdWJlLWFwaXNlcnZlci1zZXJ2
46 | aWNlLW5ldHdvcmstc2lnbmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
47 | AQEAu42Zh68Ay15gf6okTes2eQDReLdg4MQoJi3ifxBRHmjC6k+4C+HZYr10j0ge
48 | gqLHLBwhotaaMOW46gCacc/qK9Nk4J92WrFTlHoLOIOsj/R7iali1036l8NzCKq+
49 | v8qG3b1VWwqt/tBWjTqJDQndf/ZMlmpu4kpH8yjSGyMfZx7z5MkHYpkSD5Nfs5pu
50 | o3qBW6CJHbsuUgf44+/sef8OvuNMtJovucJDGyyslTilDUQURkJg/kzL8VVXsiTB
51 | tRfGDIpCrm+hf8aSQMn3DElF98b2PPkS/OsyPjQF26MCbMwKdvvIzr3EclZRxyWA
52 | pHkReRuzDO6KXuP+7T8F6fla3wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAqQwDwYD
53 | VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQURnQh03q2kBhBKLcR5E2K1v7oVbYwDQYJ
54 | KoZIhvcNAQELBQADggEBAD9py37rC4+SOfEMcklfVjqCiTYQLlIzw89HRz5Pws90
55 | /mh7boNtZ1dOvgFFiabR98/nushJ8RZQz6k4FZclsUTnOEnTyFUWQIhAI3Cx6H78
56 | yb7zM8xS6hiNs5gWe1I1VKftO0fYtGxF8XqrDVY94hLX3VFXJiCDn1Z8prfvDUya
57 | bQKqrY14PoSN2A2/mE7kI1NgC2GtUmULvJVOvrA/SorkXKCs9r0ZjuwZ3IWgjBrK
58 | EqL5tyjmVTy7TquLDLlSOl11YSddsi+RID6H7uqY0Ig4vzg9aupUxz6aXflZ4mZv
59 | tCvMV5eqKXNYu8Yan47fjonE9JPgPf7B3HzMCNWKnN4=
60 | -----END CERTIFICATE-----
61 | -----BEGIN CERTIFICATE-----
62 | MIIC7TCCAdWgAwIBAgIBATANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtpbmdy
63 | ZXNzLW9wZXJhdG9yQDE1NTkxOTQzOTQwHhcNMTkwNTMwMDUzMzEzWhcNMjEwNTI5
64 | MDUzMzE0WjAmMSQwIgYDVQQDDBtpbmdyZXNzLW9wZXJhdG9yQDE1NTkxOTQzOTQw
65 | ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDE7vYkjs9dCkFEV7+PCG0+
66 | GOQRJjlcrlzBxzwV7urh1j4WTYopUUVb+hbF3GV4TYD+u/cNM8hBIiRtrV0jCJ9d
67 | hpYoPhffMdhJiVauXsE1E/AM2JuWboi9KPXsYufqFU3M/WVodmXFWfvoGpTHTF6l
68 | Iyag5KF6M8tzQmh29+0uGEC7JtA+RTxAejqdgXYtsXQ1KGkWZFRbfSerjCIEFOZ6
69 | Or+F+puuHdFGkzronz99oI11me0wy8JeGsOtMeUGMdmMKMQDnpWv5OxjgCSrpP1V
70 | jiZ1LEQxoEX8f4No7VhECDKsnegrd6wv3I8IoU5IkYBp5C6DXW68rR9PHmBfV+mp
71 | AgMBAAGjJjAkMA4GA1UdDwEB/wQEAwICpDASBgNVHRMBAf8ECDAGAQH/AgEAMA0G
72 | CSqGSIb3DQEBCwUAA4IBAQAlazxxYnEtvJVtQGc54FOpbJfckVl6ofpDM+kY6l+Y
73 | SahzAC50tV3+RQnhiIjbxF1e9suoYzRd1QvdlhwXkrIsG/OzG6n3RiZDLU9VQDLI
74 | e8GYo+KxG4whRn4HGlnUfpXRYt+yqJV2rYUmSgsfl25YQqtSvOgq7iqSveM9eXRt
75 | CbJFAeM4lVxoGAVMbIgcQo+Nz2wu6rrFSizt2jYQfo3fazQSX6lEbQyYs9U2IzQS
76 | uLjNtAPMfv8rIpFxPB315YIp9ZGLWqnNb6mbeZZitWxfHLBtYLjSNiCUmMVKsVOu
77 | yE1/ll1ITNATextdMG92ErYT1ibaPk+DSNHSGONuKWAd
78 | -----END CERTIFICATE-----
79 |
--------------------------------------------------------------------------------
/src/test/resources/grant.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1beta1
2 | kind: ClusterRoleBinding
3 | metadata:
4 | name: default-view
5 | roleRef:
6 | apiGroup: rbac.authorization.k8s.io
7 | kind: ClusterRole
8 | name: view
9 | subjects:
10 | - kind: ServiceAccount
11 | name: default
12 | namespace: default
13 |
--------------------------------------------------------------------------------
/src/test/resources/pods.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "PodList",
3 | "apiVersion": "v1",
4 | "items": [
5 | {
6 | "metadata": {
7 | "name": "eap-app-1-43wra",
8 | "namespace": "dward"
9 | },
10 | "spec": {
11 | "containers": [
12 | {
13 | "name": "eap-app",
14 | "ports": [
15 | {
16 | "name": "http",
17 | "containerPort": 8080,
18 | "protocol": "TCP"
19 | },
20 | {
21 | "name": "ping",
22 | "containerPort": 8888,
23 | "protocol": "TCP"
24 | }
25 | ]
26 | }
27 | ],
28 | "serviceAccount": "default",
29 | "host": "localhost"
30 | },
31 | "status": {
32 | "phase": "Running",
33 | "conditions": [
34 | {
35 | "type": "Ready",
36 | "status": "True"
37 | }
38 | ],
39 | "hostIP": "127.0.0.1",
40 | "podIP": "127.0.0.1"
41 | }
42 | },
43 | {
44 | "metadata": {
45 | "name": "eap-app-1-dctpw",
46 | "namespace": "dward"
47 | },
48 | "spec": {
49 | "containers": [
50 | {
51 | "name": "eap-app",
52 | "ports": [
53 | {
54 | "name": "http",
55 | "containerPort": 8080,
56 | "protocol": "TCP"
57 | },
58 | {
59 | "name": "ping",
60 | "containerPort": 8888,
61 | "protocol": "TCP"
62 | }
63 | ]
64 | }
65 | ],
66 | "serviceAccount": "default",
67 | "host": "localhost"
68 | },
69 | "status": {
70 | "phase": "Running",
71 | "conditions": [
72 | {
73 | "type": "Ready",
74 | "status": "True"
75 | }
76 | ],
77 | "hostIP": "192.168.0.1",
78 | "podIP": "192.168.0.1"
79 | }
80 | }
81 | ]
82 | }
--------------------------------------------------------------------------------
/src/test/resources/pods_without_ports.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "PodList",
3 | "apiVersion": "v1",
4 | "metadata": {
5 | "selfLink": "\/api\/v1\/namespaces\/myproject\/pods",
6 | "resourceVersion": "2548"
7 | },
8 | "items": [
9 | {
10 | "metadata": {
11 | "name": "infinispan-simple-tutorials-kubernetes-5-n0xo2",
12 | "generateName": "infinispan-simple-tutorials-kubernetes-5-",
13 | "namespace": "myproject",
14 | "selfLink": "\/api\/v1\/namespaces\/myproject\/pods\/infinispan-simple-tutorials-kubernetes-5-n0xo2",
15 | "uid": "e9040d4c-4444-11e6-a66e-54ee751d46e3",
16 | "resourceVersion": "2469",
17 | "creationTimestamp": "2016-07-07T13:15:43Z",
18 | "labels": {
19 | "deployment": "infinispan-simple-tutorials-kubernetes-5",
20 | "deploymentconfig": "infinispan-simple-tutorials-kubernetes",
21 | "group": "org.infinispan.tutorial.simple",
22 | "project": "infinispan-simple-tutorials-kubernetes",
23 | "provider": "fabric8",
24 | "version": "1.0.0-SNAPSHOT"
25 | },
26 | "annotations": {
27 | "fabric8.io\/metrics-path": "dashboard\/file\/kubernetes-pods.json\/?var-project=infinispan-simple-tutorials-kubernetes&var-version=1.0.0-SNAPSHOT",
28 | "kubernetes.io\/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"ReplicationController\",\"namespace\":\"myproject\",\"name\":\"infinispan-simple-tutorials-kubernetes-5\",\"uid\":\"d7d7a6d4-4444-11e6-a66e-54ee751d46e3\",\"apiVersion\":\"v1\",\"resourceVersion\":\"2449\"}}\n",
29 | "openshift.io\/deployment-config.latest-version": "5",
30 | "openshift.io\/deployment-config.name": "infinispan-simple-tutorials-kubernetes",
31 | "openshift.io\/deployment.name": "infinispan-simple-tutorials-kubernetes-5",
32 | "openshift.io\/scc": "restricted"
33 | }
34 | },
35 | "spec": {
36 | "volumes": [
37 | {
38 | "name": "default-token-63adh",
39 | "secret": {
40 | "secretName": "default-token-63adh"
41 | }
42 | }
43 | ],
44 | "containers": [
45 | {
46 | "name": "infinispan-kubernetes",
47 | "image": "infinispan\/infinispan-simple-tutorials-kubernetes:1.0.0-SNAPSHOT",
48 | "ports": [
49 | {
50 | "containerPort": 8888,
51 | "protocol": "TCP"
52 | }
53 | ],
54 | "env": [
55 | {
56 | "name": "KUBERNETES_NAMESPACE",
57 | "valueFrom": {
58 | "fieldRef": {
59 | "apiVersion": "v1",
60 | "fieldPath": "metadata.namespace"
61 | }
62 | }
63 | }
64 | ],
65 | "resources": {
66 |
67 | },
68 | "volumeMounts": [
69 | {
70 | "name": "default-token-63adh",
71 | "readOnly": true,
72 | "mountPath": "\/var\/run\/secrets\/kubernetes.io\/serviceaccount"
73 | }
74 | ],
75 | "terminationMessagePath": "\/dev\/termination-log",
76 | "imagePullPolicy": "IfNotPresent",
77 | "securityContext": {
78 | "capabilities": {
79 | "drop": [
80 | "KILL",
81 | "MKNOD",
82 | "SETGID",
83 | "SETUID",
84 | "SYS_CHROOT"
85 | ]
86 | },
87 | "privileged": false,
88 | "seLinuxOptions": {
89 | "level": "s0:c6,c0"
90 | },
91 | "runAsUser": 1000030000
92 | }
93 | }
94 | ],
95 | "restartPolicy": "Always",
96 | "terminationGracePeriodSeconds": 30,
97 | "dnsPolicy": "ClusterFirst",
98 | "host": "slaskawi",
99 | "serviceAccountName": "default",
100 | "serviceAccount": "default",
101 | "nodeName": "slaskawi",
102 | "securityContext": {
103 | "seLinuxOptions": {
104 | "level": "s0:c6,c0"
105 | },
106 | "fsGroup": 1000030000
107 | },
108 | "imagePullSecrets": [
109 | {
110 | "name": "default-dockercfg-4rour"
111 | }
112 | ]
113 | },
114 | "status": {
115 | "phase": "Running",
116 | "conditions": [
117 | {
118 | "type": "Ready",
119 | "status": "True",
120 | "lastProbeTime": null,
121 | "lastTransitionTime": "2016-07-07T13:15:47Z"
122 | }
123 | ],
124 | "hostIP": "192.168.0.17",
125 | "podIP": "172.17.0.5",
126 | "startTime": "2016-07-07T13:15:43Z",
127 | "containerStatuses": [
128 | {
129 | "name": "infinispan-kubernetes",
130 | "state": {
131 | "running": {
132 | "startedAt": "2016-07-07T13:15:47Z"
133 | }
134 | },
135 | "lastState": {
136 |
137 | },
138 | "ready": true,
139 | "restartCount": 0,
140 | "image": "infinispan\/infinispan-simple-tutorials-kubernetes:1.0.0-SNAPSHOT",
141 | "imageID": "docker:\/\/sha256:e5485332ce388f586afd33999254535f376caafca081689f672df864d97bd150",
142 | "containerID": "docker:\/\/c80b770006c23606ae0513e28b927d3035070f66a0d729674b4491c5dd0f0909"
143 | }
144 | ]
145 | }
146 | },
147 | {
148 | "metadata": {
149 | "name": "infinispan-simple-tutorials-kubernetes-5-r0han",
150 | "generateName": "infinispan-simple-tutorials-kubernetes-5-",
151 | "namespace": "myproject",
152 | "selfLink": "\/api\/v1\/namespaces\/myproject\/pods\/infinispan-simple-tutorials-kubernetes-5-r0han",
153 | "uid": "227d91f5-4445-11e6-a66e-54ee751d46e3",
154 | "resourceVersion": "2505",
155 | "creationTimestamp": "2016-07-07T13:17:20Z",
156 | "labels": {
157 | "deployment": "infinispan-simple-tutorials-kubernetes-5",
158 | "deploymentconfig": "infinispan-simple-tutorials-kubernetes",
159 | "group": "org.infinispan.tutorial.simple",
160 | "project": "infinispan-simple-tutorials-kubernetes",
161 | "provider": "fabric8",
162 | "version": "1.0.0-SNAPSHOT"
163 | },
164 | "annotations": {
165 | "fabric8.io\/metrics-path": "dashboard\/file\/kubernetes-pods.json\/?var-project=infinispan-simple-tutorials-kubernetes&var-version=1.0.0-SNAPSHOT",
166 | "kubernetes.io\/created-by": "{\"kind\":\"SerializedReference\",\"apiVersion\":\"v1\",\"reference\":{\"kind\":\"ReplicationController\",\"namespace\":\"myproject\",\"name\":\"infinispan-simple-tutorials-kubernetes-5\",\"uid\":\"d7d7a6d4-4444-11e6-a66e-54ee751d46e3\",\"apiVersion\":\"v1\",\"resourceVersion\":\"2488\"}}\n",
167 | "openshift.io\/deployment-config.latest-version": "5",
168 | "openshift.io\/deployment-config.name": "infinispan-simple-tutorials-kubernetes",
169 | "openshift.io\/deployment.name": "infinispan-simple-tutorials-kubernetes-5",
170 | "openshift.io\/scc": "restricted"
171 | }
172 | },
173 | "spec": {
174 | "volumes": [
175 | {
176 | "name": "default-token-63adh",
177 | "secret": {
178 | "secretName": "default-token-63adh"
179 | }
180 | }
181 | ],
182 | "containers": [
183 | {
184 | "name": "infinispan-kubernetes",
185 | "image": "infinispan\/infinispan-simple-tutorials-kubernetes:1.0.0-SNAPSHOT",
186 | "ports": [
187 | {
188 | "containerPort": 8888,
189 | "protocol": "TCP"
190 | }
191 | ],
192 | "env": [
193 | {
194 | "name": "KUBERNETES_NAMESPACE",
195 | "valueFrom": {
196 | "fieldRef": {
197 | "apiVersion": "v1",
198 | "fieldPath": "metadata.namespace"
199 | }
200 | }
201 | }
202 | ],
203 | "resources": {
204 |
205 | },
206 | "volumeMounts": [
207 | {
208 | "name": "default-token-63adh",
209 | "readOnly": true,
210 | "mountPath": "\/var\/run\/secrets\/kubernetes.io\/serviceaccount"
211 | }
212 | ],
213 | "terminationMessagePath": "\/dev\/termination-log",
214 | "imagePullPolicy": "IfNotPresent",
215 | "securityContext": {
216 | "capabilities": {
217 | "drop": [
218 | "KILL",
219 | "MKNOD",
220 | "SETGID",
221 | "SETUID",
222 | "SYS_CHROOT"
223 | ]
224 | },
225 | "privileged": false,
226 | "seLinuxOptions": {
227 | "level": "s0:c6,c0"
228 | },
229 | "runAsUser": 1000030000
230 | }
231 | }
232 | ],
233 | "restartPolicy": "Always",
234 | "terminationGracePeriodSeconds": 30,
235 | "dnsPolicy": "ClusterFirst",
236 | "host": "slaskawi",
237 | "serviceAccountName": "default",
238 | "serviceAccount": "default",
239 | "nodeName": "slaskawi",
240 | "securityContext": {
241 | "seLinuxOptions": {
242 | "level": "s0:c6,c0"
243 | },
244 | "fsGroup": 1000030000
245 | },
246 | "imagePullSecrets": [
247 | {
248 | "name": "default-dockercfg-4rour"
249 | }
250 | ]
251 | },
252 | "status": {
253 | "phase": "Running",
254 | "conditions": [
255 | {
256 | "type": "Ready",
257 | "status": "True",
258 | "lastProbeTime": null,
259 | "lastTransitionTime": "2016-07-07T13:17:24Z"
260 | }
261 | ],
262 | "hostIP": "192.168.0.17",
263 | "podIP": "172.17.0.2",
264 | "startTime": "2016-07-07T13:17:20Z",
265 | "containerStatuses": [
266 | {
267 | "name": "infinispan-kubernetes",
268 | "state": {
269 | "running": {
270 | "startedAt": "2016-07-07T13:17:23Z"
271 | }
272 | },
273 | "lastState": {
274 |
275 | },
276 | "ready": true,
277 | "restartCount": 0,
278 | "image": "infinispan\/infinispan-simple-tutorials-kubernetes:1.0.0-SNAPSHOT",
279 | "imageID": "docker:\/\/sha256:e5485332ce388f586afd33999254535f376caafca081689f672df864d97bd150",
280 | "containerID": "docker:\/\/1ee2b9b5d350d364df3b787e1a6f13633f68f328a928b503874efa57e60a7c45"
281 | }
282 | ]
283 | }
284 | }
285 | ]
286 | }
--------------------------------------------------------------------------------
/src/test/resources/replicaset_rolling_update.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "PodList",
3 | "apiVersion": "v1",
4 | "metadata": {
5 | "selfLink": "/api/v1/namespaces/default/pods",
6 | "resourceVersion": "414433"
7 | },
8 | "items": [
9 | {
10 | "metadata": {
11 | "name": "idp-6569c544b-f72mb",
12 | "generateName": "idp-6569c544b-",
13 | "namespace": "default",
14 | "selfLink": "/api/v1/namespaces/default/pods/idp-6569c544b-f72mb",
15 | "uid": "b5ab2340-a163-11e9-ba8c-001c42897fd6",
16 | "resourceVersion": "406742",
17 | "creationTimestamp": "2019-07-08T09:35:23Z",
18 | "labels": {
19 | "app": "idp-backend",
20 | "group": "com.odin.idp",
21 | "pod-template-hash": "6569c544b"
22 | },
23 | "ownerReferences": [{
24 | "apiVersion": "apps/v1",
25 | "kind": "ReplicaSet",
26 | "name": "idp-6569c544b",
27 | "uid": "b596013d-a163-11e9-ba8c-001c42897fd6",
28 | "controller": true,
29 | "blockOwnerDeletion": true
30 | }
31 | ]
32 | },
33 | "spec": {
34 | "volumes": [{
35 | "name": "default-token-w9wpf",
36 | "secret": {
37 | "secretName": "default-token-w9wpf",
38 | "defaultMode": 420
39 | }
40 | }
41 | ],
42 | "containers": [{
43 | "name": "idp-backend",
44 | "image": "skeleton.repo.int.zone/idp-backend:1.0.1278",
45 | "ports": [{
46 | "name": "wildfly",
47 | "containerPort": 8081,
48 | "protocol": "TCP"
49 | }, {
50 | "name": "debug",
51 | "containerPort": 8787,
52 | "protocol": "TCP"
53 | }, {
54 | "name": "jgroups",
55 | "containerPort": 7600,
56 | "protocol": "TCP"
57 | }
58 | ],
59 | "env": [{
60 | "name": "OAUTH_KEY",
61 | "valueFrom": {
62 | "secretKeyRef": {
63 | "name": "idp",
64 | "key": "oauthkey"
65 | }
66 | }
67 | }, {
68 | "name": "OAUTH_SECRET",
69 | "valueFrom": {
70 | "secretKeyRef": {
71 | "name": "idp",
72 | "key": "oauthsecret"
73 | }
74 | }
75 | }, {
76 | "name": "JAVA_HEAP_SIZE",
77 | "value": "-Xms512m -Xmx1024m"
78 | }, {
79 | "name": "DS_DB_NAME",
80 | "value": "idpdb"
81 | }, {
82 | "name": "DS_LOGIN",
83 | "valueFrom": {
84 | "secretKeyRef": {
85 | "name": "idp",
86 | "key": "dslogin"
87 | }
88 | }
89 | }, {
90 | "name": "DS_PASSWORD",
91 | "valueFrom": {
92 | "secretKeyRef": {
93 | "name": "idp",
94 | "key": "dspassword"
95 | }
96 | }
97 | }, {
98 | "name": "JBOSS_ADMIN_PASSWORD",
99 | "valueFrom": {
100 | "secretKeyRef": {
101 | "name": "idp",
102 | "key": "jbossadminpassword"
103 | }
104 | }
105 | }, {
106 | "name": "DS_HOST",
107 | "value": "postgres-postgresql.default.svc.cluster.local"
108 | }, {
109 | "name": "DS_PORT",
110 | "value": "5432"
111 | }, {
112 | "name": "MIN_DB_POOL_SIZE",
113 | "value": "1"
114 | }, {
115 | "name": "MAX_DB_POOL_SIZE",
116 | "value": "16"
117 | }, {
118 | "name": "JDBC_CONNECTION_PARAMS",
119 | "value": "?ApplicationName=idp-app"
120 | }, {
121 | "name": "KEYCLOAK_LOGLEVEL",
122 | "value": "DEBUG"
123 | }
124 | ],
125 | "resources": {
126 | "limits": {
127 | "cpu": "8",
128 | "memory": "4Gi"
129 | },
130 | "requests": {
131 | "cpu": "50m",
132 | "memory": "1Gi"
133 | }
134 | },
135 | "volumeMounts": [{
136 | "name": "default-token-w9wpf",
137 | "readOnly": true,
138 | "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount"
139 | }
140 | ],
141 | "livenessProbe": {
142 | "httpGet": {
143 | "path": "/rest/application/livenessProbe",
144 | "port": "wildfly",
145 | "scheme": "HTTPS"
146 | },
147 | "initialDelaySeconds": 40,
148 | "timeoutSeconds": 5,
149 | "periodSeconds": 60,
150 | "successThreshold": 1,
151 | "failureThreshold": 30000
152 | },
153 | "readinessProbe": {
154 | "httpGet": {
155 | "path": "/rest/application/readinessProbe",
156 | "port": "wildfly",
157 | "scheme": "HTTPS"
158 | },
159 | "initialDelaySeconds": 40,
160 | "timeoutSeconds": 5,
161 | "periodSeconds": 5,
162 | "successThreshold": 1,
163 | "failureThreshold": 30000
164 | },
165 | "terminationMessagePath": "/dev/termination-log",
166 | "terminationMessagePolicy": "File",
167 | "imagePullPolicy": "IfNotPresent"
168 | }
169 | ],
170 | "restartPolicy": "Always",
171 | "terminationGracePeriodSeconds": 30,
172 | "dnsPolicy": "ClusterFirst",
173 | "serviceAccountName": "default",
174 | "serviceAccount": "default",
175 | "nodeName": "kumaster-3a8cddfe6d8a.aqa.int.zone",
176 | "securityContext": {},
177 | "imagePullSecrets": [{
178 | "name": "a8n-docker-registry"
179 | }
180 | ],
181 | "schedulerName": "default-scheduler",
182 | "tolerations": [{
183 | "key": "node.kubernetes.io/not-ready",
184 | "operator": "Exists",
185 | "effect": "NoExecute",
186 | "tolerationSeconds": 300
187 | }, {
188 | "key": "node.kubernetes.io/unreachable",
189 | "operator": "Exists",
190 | "effect": "NoExecute",
191 | "tolerationSeconds": 300
192 | }
193 | ],
194 | "priority": 0
195 | },
196 | "status": {
197 | "phase": "Running",
198 | "conditions": [{
199 | "type": "Initialized",
200 | "status": "True",
201 | "lastProbeTime": null,
202 | "lastTransitionTime": "2019-07-08T09:35:23Z"
203 | }, {
204 | "type": "Ready",
205 | "status": "True",
206 | "lastProbeTime": null,
207 | "lastTransitionTime": "2019-07-08T09:36:48Z"
208 | }, {
209 | "type": "ContainersReady",
210 | "status": "True",
211 | "lastProbeTime": null,
212 | "lastTransitionTime": "2019-07-08T09:36:48Z"
213 | }, {
214 | "type": "PodScheduled",
215 | "status": "True",
216 | "lastProbeTime": null,
217 | "lastTransitionTime": "2019-07-08T09:35:23Z"
218 | }
219 | ],
220 | "hostIP": "10.26.163.91",
221 | "podIP": "127.0.0.1",
222 | "startTime": "2019-07-08T09:35:23Z",
223 | "containerStatuses": [{
224 | "name": "idp-backend",
225 | "state": {
226 | "running": {
227 | "startedAt": "2019-07-08T09:35:31Z"
228 | }
229 | },
230 | "lastState": {},
231 | "ready": true,
232 | "restartCount": 0,
233 | "image": "skeleton.repo.int.zone/idp-backend:1.0.1278",
234 | "imageID": "docker-pullable://skeleton.repo.int.zone/idp-backend@sha256:2079cd6f976f0c7b841db2ca00cc5a704c9b781cc2aaa071eab893e9188a7698",
235 | "containerID": "docker://408f06380d86be10ad1bd553d9cea47d2278c1af39c7ad4e9833386aa716e436"
236 | }
237 | ],
238 | "qosClass": "Burstable"
239 | }
240 | },
241 | {
242 | "metadata": {
243 | "name": "idp-aae51544b-a80bc",
244 | "generateName": "idp-aae51544b-",
245 | "namespace": "default",
246 | "selfLink": "/api/v1/namespaces/default/pods/idp-aae51544b-a80bc",
247 | "uid": "ce525630-a163-11e9-ba8c-001c42897fff",
248 | "resourceVersion": "406749",
249 | "creationTimestamp": "2019-07-08T09:39:23Z",
250 | "labels": {
251 | "app": "idp-backend",
252 | "group": "com.odin.idp",
253 | "pod-template-hash": "6569c556b"
254 | },
255 | "ownerReferences": [{
256 | "apiVersion": "apps/v1",
257 | "kind": "ReplicaSet",
258 | "name": "idp-aae51544b",
259 | "uid": "9eb0013d-a163-11e9-ba8c-001c42897fd6",
260 | "controller": true,
261 | "blockOwnerDeletion": true
262 | }
263 | ]
264 | },
265 | "spec": {
266 | "volumes": [{
267 | "name": "default-token-w9wpf",
268 | "secret": {
269 | "secretName": "default-token-w9wpf",
270 | "defaultMode": 420
271 | }
272 | }
273 | ],
274 | "containers": [{
275 | "name": "idp-backend",
276 | "image": "skeleton.repo.int.zone/idp-backend:1.0.1279",
277 | "ports": [{
278 | "name": "wildfly",
279 | "containerPort": 8081,
280 | "protocol": "TCP"
281 | }, {
282 | "name": "debug",
283 | "containerPort": 8787,
284 | "protocol": "TCP"
285 | }, {
286 | "name": "jgroups",
287 | "containerPort": 7600,
288 | "protocol": "TCP"
289 | }
290 | ],
291 | "env": [{
292 | "name": "OAUTH_KEY",
293 | "valueFrom": {
294 | "secretKeyRef": {
295 | "name": "idp",
296 | "key": "oauthkey"
297 | }
298 | }
299 | }, {
300 | "name": "OAUTH_SECRET",
301 | "valueFrom": {
302 | "secretKeyRef": {
303 | "name": "idp",
304 | "key": "oauthsecret"
305 | }
306 | }
307 | }, {
308 | "name": "JAVA_HEAP_SIZE",
309 | "value": "-Xms512m -Xmx1024m"
310 | }, {
311 | "name": "DS_DB_NAME",
312 | "value": "idpdb"
313 | }, {
314 | "name": "DS_LOGIN",
315 | "valueFrom": {
316 | "secretKeyRef": {
317 | "name": "idp",
318 | "key": "dslogin"
319 | }
320 | }
321 | }, {
322 | "name": "DS_PASSWORD",
323 | "valueFrom": {
324 | "secretKeyRef": {
325 | "name": "idp",
326 | "key": "dspassword"
327 | }
328 | }
329 | }, {
330 | "name": "JBOSS_ADMIN_PASSWORD",
331 | "valueFrom": {
332 | "secretKeyRef": {
333 | "name": "idp",
334 | "key": "jbossadminpassword"
335 | }
336 | }
337 | }, {
338 | "name": "DS_HOST",
339 | "value": "postgres-postgresql.default.svc.cluster.local"
340 | }, {
341 | "name": "DS_PORT",
342 | "value": "5432"
343 | }, {
344 | "name": "MIN_DB_POOL_SIZE",
345 | "value": "1"
346 | }, {
347 | "name": "MAX_DB_POOL_SIZE",
348 | "value": "16"
349 | }, {
350 | "name": "JDBC_CONNECTION_PARAMS",
351 | "value": "?ApplicationName=idp-app"
352 | }, {
353 | "name": "KEYCLOAK_LOGLEVEL",
354 | "value": "DEBUG"
355 | }
356 | ],
357 | "resources": {
358 | "limits": {
359 | "cpu": "8",
360 | "memory": "4Gi"
361 | },
362 | "requests": {
363 | "cpu": "50m",
364 | "memory": "1Gi"
365 | }
366 | },
367 | "volumeMounts": [{
368 | "name": "default-token-w9wpf",
369 | "readOnly": true,
370 | "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount"
371 | }
372 | ],
373 | "livenessProbe": {
374 | "httpGet": {
375 | "path": "/rest/application/livenessProbe",
376 | "port": "wildfly",
377 | "scheme": "HTTPS"
378 | },
379 | "initialDelaySeconds": 40,
380 | "timeoutSeconds": 5,
381 | "periodSeconds": 60,
382 | "successThreshold": 1,
383 | "failureThreshold": 30000
384 | },
385 | "readinessProbe": {
386 | "httpGet": {
387 | "path": "/rest/application/readinessProbe",
388 | "port": "wildfly",
389 | "scheme": "HTTPS"
390 | },
391 | "initialDelaySeconds": 40,
392 | "timeoutSeconds": 5,
393 | "periodSeconds": 5,
394 | "successThreshold": 1,
395 | "failureThreshold": 30000
396 | },
397 | "terminationMessagePath": "/dev/termination-log",
398 | "terminationMessagePolicy": "File",
399 | "imagePullPolicy": "IfNotPresent"
400 | }
401 | ],
402 | "restartPolicy": "Always",
403 | "terminationGracePeriodSeconds": 30,
404 | "dnsPolicy": "ClusterFirst",
405 | "serviceAccountName": "default",
406 | "serviceAccount": "default",
407 | "nodeName": "kumaster-3a8cddfe6d8a.aqa.int.zone",
408 | "securityContext": {},
409 | "imagePullSecrets": [{
410 | "name": "a8n-docker-registry"
411 | }
412 | ],
413 | "schedulerName": "default-scheduler",
414 | "tolerations": [{
415 | "key": "node.kubernetes.io/not-ready",
416 | "operator": "Exists",
417 | "effect": "NoExecute",
418 | "tolerationSeconds": 300
419 | }, {
420 | "key": "node.kubernetes.io/unreachable",
421 | "operator": "Exists",
422 | "effect": "NoExecute",
423 | "tolerationSeconds": 300
424 | }
425 | ],
426 | "priority": 0
427 | },
428 | "status": {
429 | "phase": "Running",
430 | "conditions": [{
431 | "type": "Initialized",
432 | "status": "True",
433 | "lastProbeTime": null,
434 | "lastTransitionTime": "2019-07-08T09:35:23Z"
435 | }, {
436 | "type": "Ready",
437 | "status": "True",
438 | "lastProbeTime": null,
439 | "lastTransitionTime": "2019-07-08T09:36:48Z"
440 | }, {
441 | "type": "ContainersReady",
442 | "status": "True",
443 | "lastProbeTime": null,
444 | "lastTransitionTime": "2019-07-08T09:36:48Z"
445 | }, {
446 | "type": "PodScheduled",
447 | "status": "True",
448 | "lastProbeTime": null,
449 | "lastTransitionTime": "2019-07-08T09:35:23Z"
450 | }
451 | ],
452 | "hostIP": "10.26.163.91",
453 | "podIP": "127.0.0.1",
454 | "startTime": "2019-07-08T09:35:23Z",
455 | "containerStatuses": [{
456 | "name": "idp-backend",
457 | "state": {
458 | "running": {
459 | "startedAt": "2019-07-08T09:35:31Z"
460 | }
461 | },
462 | "lastState": {},
463 | "ready": true,
464 | "restartCount": 0,
465 | "image": "skeleton.repo.int.zone/idp-backend:1.0.1279",
466 | "imageID": "docker-pullable://skeleton.repo.int.zone/idp-backend@sha256:aaaaad6f976f0c7b841db2ca00cc5a704c9b781cc2aaa071eab893e9188a7698",
467 | "containerID": "docker://aaaaaa380d86be10ad1bd553d9cea47d2278c1af39c7ad4e9833386aa716e436"
468 | }
469 | ],
470 | "qosClass": "Burstable"
471 | }
472 | }
473 |
474 | ]
475 | }
476 |
--------------------------------------------------------------------------------
/src/test/resources/statefulset_rolling_update.json:
--------------------------------------------------------------------------------
1 | {
2 | "apiVersion": "v1",
3 | "items": [
4 | {
5 | "apiVersion": "v1",
6 | "kind": "Pod",
7 | "metadata": {
8 | "annotations": {
9 | "k8s.v1.cni.cncf.io/networks-status": "[{\n \"name\": \"openshift-sdn\",\n \"interface\": \"eth0\",\n \"ips\": [\n \"10.128.0.221\"\n ],\n \"default\": true,\n \"dns\": {}\n}]",
10 | "openshift.io/scc": "restricted"
11 | },
12 | "creationTimestamp": "2019-10-10T08:33:38Z",
13 | "generateName": "keycloak-",
14 | "labels": {
15 | "application": "keycloak",
16 | "component": "keycloak",
17 | "controller-revision-hash": "keycloak-5f6594785b",
18 | "statefulset.kubernetes.io/pod-name": "keycloak-0"
19 | },
20 | "name": "keycloak-0",
21 | "namespace": "keycloak",
22 | "ownerReferences": [
23 | {
24 | "apiVersion": "apps/v1",
25 | "blockOwnerDeletion": true,
26 | "controller": true,
27 | "kind": "StatefulSet",
28 | "name": "keycloak",
29 | "uid": "d6e308ff-eb37-11e9-ba11-52fdfc072182"
30 | }
31 | ],
32 | "resourceVersion": "239934",
33 | "selfLink": "/api/v1/namespaces/keycloak/pods/keycloak-0",
34 | "uid": "a8111f90-eb38-11e9-ba11-52fdfc072182"
35 | },
36 | "spec": {
37 | "containers": [
38 | {
39 | "env": [
40 | {
41 | "name": "DB_SERVICE_PREFIX_MAPPING",
42 | "value": "keycloak-postgresql=DB"
43 | },
44 | {
45 | "name": "TX_DATABASE_PREFIX_MAPPING",
46 | "value": "keycloak-postgresql=DB"
47 | },
48 | {
49 | "name": "DB_JNDI",
50 | "value": "java:jboss/datasources/KeycloakDS"
51 | },
52 | {
53 | "name": "DB_SCHEMA",
54 | "value": "public"
55 | },
56 | {
57 | "name": "DB_USERNAME",
58 | "valueFrom": {
59 | "secretKeyRef": {
60 | "key": "user",
61 | "name": "keycloak-db-secret"
62 | }
63 | }
64 | },
65 | {
66 | "name": "DB_PASSWORD",
67 | "valueFrom": {
68 | "secretKeyRef": {
69 | "key": "password",
70 | "name": "keycloak-db-secret"
71 | }
72 | }
73 | },
74 | {
75 | "name": "DB_DATABASE",
76 | "value": "root"
77 | },
78 | {
79 | "name": "JGROUPS_PING_PROTOCOL",
80 | "value": "dns.DNS_PING"
81 | },
82 | {
83 | "name": "OPENSHIFT_DNS_PING_SERVICE_NAME",
84 | "value": "keycloak-discovery.keycloak.svc.cluster.local"
85 | },
86 | {
87 | "name": "SSO_ADMIN_USERNAME",
88 | "valueFrom": {
89 | "secretKeyRef": {
90 | "key": "ADMIN_USERNAME",
91 | "name": "credential-example-keycloak"
92 | }
93 | }
94 | },
95 | {
96 | "name": "SSO_ADMIN_PASSWORD",
97 | "valueFrom": {
98 | "secretKeyRef": {
99 | "key": "ADMIN_PASSWORD",
100 | "name": "credential-example-keycloak"
101 | }
102 | }
103 | }
104 | ],
105 | "image": "registry.access.redhat.com/redhat-sso-7/sso73-openshift:1.0",
106 | "imagePullPolicy": "IfNotPresent",
107 | "livenessProbe": {
108 | "failureThreshold": 3,
109 | "httpGet": {
110 | "path": "/auth/realms/master",
111 | "port": 8080,
112 | "scheme": "HTTP"
113 | },
114 | "initialDelaySeconds": 60,
115 | "periodSeconds": 10,
116 | "successThreshold": 1,
117 | "timeoutSeconds": 1
118 | },
119 | "name": "keycloak",
120 | "ports": [
121 | {
122 | "containerPort": 8443,
123 | "protocol": "TCP"
124 | },
125 | {
126 | "containerPort": 8080,
127 | "protocol": "TCP"
128 | },
129 | {
130 | "containerPort": 9990,
131 | "protocol": "TCP"
132 | },
133 | {
134 | "containerPort": 8778,
135 | "protocol": "TCP"
136 | }
137 | ],
138 | "readinessProbe": {
139 | "failureThreshold": 3,
140 | "httpGet": {
141 | "path": "/auth/realms/master",
142 | "port": 8080,
143 | "scheme": "HTTP"
144 | },
145 | "initialDelaySeconds": 10,
146 | "periodSeconds": 10,
147 | "successThreshold": 1,
148 | "timeoutSeconds": 1
149 | },
150 | "resources": {},
151 | "securityContext": {
152 | "capabilities": {
153 | "drop": [
154 | "KILL",
155 | "MKNOD",
156 | "SETGID",
157 | "SETUID"
158 | ]
159 | },
160 | "runAsUser": 1000470000
161 | },
162 | "terminationMessagePath": "/dev/termination-log",
163 | "terminationMessagePolicy": "File",
164 | "volumeMounts": [
165 | {
166 | "mountPath": "/etc/x509/https",
167 | "name": "sso-x509-https-secret"
168 | },
169 | {
170 | "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
171 | "name": "default-token-kv98v",
172 | "readOnly": true
173 | }
174 | ]
175 | }
176 | ],
177 | "dnsPolicy": "ClusterFirst",
178 | "enableServiceLinks": true,
179 | "hostname": "keycloak-0",
180 | "imagePullSecrets": [
181 | {
182 | "name": "default-dockercfg-gm7sc"
183 | }
184 | ],
185 | "nodeName": "crc-vsqrt-master-0",
186 | "priority": 0,
187 | "restartPolicy": "Always",
188 | "schedulerName": "default-scheduler",
189 | "securityContext": {
190 | "fsGroup": 1000470000,
191 | "seLinuxOptions": {
192 | "level": "s0:c22,c4"
193 | }
194 | },
195 | "serviceAccount": "default",
196 | "serviceAccountName": "default",
197 | "terminationGracePeriodSeconds": 30,
198 | "tolerations": [
199 | {
200 | "effect": "NoExecute",
201 | "key": "node.kubernetes.io/not-ready",
202 | "operator": "Exists",
203 | "tolerationSeconds": 300
204 | },
205 | {
206 | "effect": "NoExecute",
207 | "key": "node.kubernetes.io/unreachable",
208 | "operator": "Exists",
209 | "tolerationSeconds": 300
210 | }
211 | ],
212 | "volumes": [
213 | {
214 | "name": "sso-x509-https-secret",
215 | "secret": {
216 | "defaultMode": 420,
217 | "optional": true,
218 | "secretName": "sso-x509-https-secret"
219 | }
220 | },
221 | {
222 | "name": "default-token-kv98v",
223 | "secret": {
224 | "defaultMode": 420,
225 | "secretName": "default-token-kv98v"
226 | }
227 | }
228 | ]
229 | },
230 | "status": {
231 | "conditions": [
232 | {
233 | "lastProbeTime": null,
234 | "lastTransitionTime": "2019-10-10T08:35:44Z",
235 | "status": "True",
236 | "type": "Initialized"
237 | },
238 | {
239 | "lastProbeTime": null,
240 | "lastTransitionTime": "2019-10-11T06:05:00Z",
241 | "status": "True",
242 | "type": "Ready"
243 | },
244 | {
245 | "lastProbeTime": null,
246 | "lastTransitionTime": "2019-10-11T06:05:00Z",
247 | "status": "True",
248 | "type": "ContainersReady"
249 | },
250 | {
251 | "lastProbeTime": null,
252 | "lastTransitionTime": "2019-10-10T08:35:44Z",
253 | "status": "True",
254 | "type": "PodScheduled"
255 | }
256 | ],
257 | "containerStatuses": [
258 | {
259 | "containerID": "cri-o://54d7258086f50cbbfa16ef98cf78aa76f9b56c3f1529320d49740c79c79d314a",
260 | "image": "registry.access.redhat.com/redhat-sso-7/sso73-openshift:1.0",
261 | "imageID": "registry.access.redhat.com/redhat-sso-7/sso73-openshift@sha256:35740d1dbebbb4dc39ea9ce4736d5cc54675a984b1ec0f9bef67eb48e93ffe2d",
262 | "lastState": {
263 | "terminated": {
264 | "containerID": "cri-o://44739a5e5056958f79b7241451715e8463a2cdf84c88616e4a94c779d6846022",
265 | "exitCode": 127,
266 | "finishedAt": "2019-10-11T06:04:05Z",
267 | "reason": "Error",
268 | "startedAt": "2019-10-11T06:02:21Z"
269 | }
270 | },
271 | "name": "keycloak",
272 | "ready": true,
273 | "restartCount": 2,
274 | "state": {
275 | "running": {
276 | "startedAt": "2019-10-11T06:04:05Z"
277 | }
278 | }
279 | }
280 | ],
281 | "hostIP": "192.168.130.11",
282 | "phase": "Running",
283 | "podIP": "127.0.0.1",
284 | "qosClass": "BestEffort",
285 | "startTime": "2019-10-10T08:35:44Z"
286 | }
287 | },
288 | {
289 | "apiVersion": "v1",
290 | "kind": "Pod",
291 | "metadata": {
292 | "annotations": {
293 | "k8s.v1.cni.cncf.io/networks-status": "[{\n \"name\": \"openshift-sdn\",\n \"interface\": \"eth0\",\n \"ips\": [\n \"10.128.0.234\"\n ],\n \"default\": true,\n \"dns\": {}\n}]",
294 | "openshift.io/scc": "restricted"
295 | },
296 | "creationTimestamp": "2019-10-11T06:26:03Z",
297 | "deletionGracePeriodSeconds": 30,
298 | "deletionTimestamp": "2019-10-11T06:53:17Z",
299 | "generateName": "keycloak-",
300 | "labels": {
301 | "application": "keycloak",
302 | "component": "keycloak",
303 | "controller-revision-hash": "keycloak-5f6594785b",
304 | "statefulset.kubernetes.io/pod-name": "keycloak-1"
305 | },
306 | "name": "keycloak-1",
307 | "namespace": "keycloak",
308 | "ownerReferences": [
309 | {
310 | "apiVersion": "apps/v1",
311 | "blockOwnerDeletion": true,
312 | "controller": true,
313 | "kind": "StatefulSet",
314 | "name": "keycloak",
315 | "uid": "d6e308ff-eb37-11e9-ba11-52fdfc072182"
316 | }
317 | ],
318 | "resourceVersion": "249940",
319 | "selfLink": "/api/v1/namespaces/keycloak/pods/keycloak-1",
320 | "uid": "0037cefc-ebf0-11e9-8261-52fdfc072182"
321 | },
322 | "spec": {
323 | "containers": [
324 | {
325 | "env": [
326 | {
327 | "name": "DB_SERVICE_PREFIX_MAPPING",
328 | "value": "keycloak-postgresql=DB"
329 | },
330 | {
331 | "name": "TX_DATABASE_PREFIX_MAPPING",
332 | "value": "keycloak-postgresql=DB"
333 | },
334 | {
335 | "name": "DB_JNDI",
336 | "value": "java:jboss/datasources/KeycloakDS"
337 | },
338 | {
339 | "name": "DB_SCHEMA",
340 | "value": "public"
341 | },
342 | {
343 | "name": "DB_USERNAME",
344 | "valueFrom": {
345 | "secretKeyRef": {
346 | "key": "user",
347 | "name": "keycloak-db-secret"
348 | }
349 | }
350 | },
351 | {
352 | "name": "DB_PASSWORD",
353 | "valueFrom": {
354 | "secretKeyRef": {
355 | "key": "password",
356 | "name": "keycloak-db-secret"
357 | }
358 | }
359 | },
360 | {
361 | "name": "DB_DATABASE",
362 | "value": "root"
363 | },
364 | {
365 | "name": "JGROUPS_PING_PROTOCOL",
366 | "value": "dns.DNS_PING"
367 | },
368 | {
369 | "name": "OPENSHIFT_DNS_PING_SERVICE_NAME",
370 | "value": "keycloak-discovery.keycloak.svc.cluster.local"
371 | },
372 | {
373 | "name": "SSO_ADMIN_USERNAME",
374 | "valueFrom": {
375 | "secretKeyRef": {
376 | "key": "ADMIN_USERNAME",
377 | "name": "credential-example-keycloak"
378 | }
379 | }
380 | },
381 | {
382 | "name": "SSO_ADMIN_PASSWORD",
383 | "valueFrom": {
384 | "secretKeyRef": {
385 | "key": "ADMIN_PASSWORD",
386 | "name": "credential-example-keycloak"
387 | }
388 | }
389 | }
390 | ],
391 | "image": "registry.access.redhat.com/redhat-sso-7/sso73-openshift:1.0",
392 | "imagePullPolicy": "IfNotPresent",
393 | "livenessProbe": {
394 | "failureThreshold": 3,
395 | "httpGet": {
396 | "path": "/auth/realms/master",
397 | "port": 8080,
398 | "scheme": "HTTP"
399 | },
400 | "initialDelaySeconds": 60,
401 | "periodSeconds": 10,
402 | "successThreshold": 1,
403 | "timeoutSeconds": 1
404 | },
405 | "name": "keycloak",
406 | "ports": [
407 | {
408 | "containerPort": 8443,
409 | "protocol": "TCP"
410 | },
411 | {
412 | "containerPort": 8080,
413 | "protocol": "TCP"
414 | },
415 | {
416 | "containerPort": 9990,
417 | "protocol": "TCP"
418 | },
419 | {
420 | "containerPort": 8778,
421 | "protocol": "TCP"
422 | }
423 | ],
424 | "readinessProbe": {
425 | "failureThreshold": 3,
426 | "httpGet": {
427 | "path": "/auth/realms/master",
428 | "port": 8080,
429 | "scheme": "HTTP"
430 | },
431 | "initialDelaySeconds": 10,
432 | "periodSeconds": 10,
433 | "successThreshold": 1,
434 | "timeoutSeconds": 1
435 | },
436 | "resources": {},
437 | "securityContext": {
438 | "capabilities": {
439 | "drop": [
440 | "KILL",
441 | "MKNOD",
442 | "SETGID",
443 | "SETUID"
444 | ]
445 | },
446 | "runAsUser": 1000470000
447 | },
448 | "terminationMessagePath": "/dev/termination-log",
449 | "terminationMessagePolicy": "File",
450 | "volumeMounts": [
451 | {
452 | "mountPath": "/etc/x509/https",
453 | "name": "sso-x509-https-secret"
454 | },
455 | {
456 | "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
457 | "name": "default-token-kv98v",
458 | "readOnly": true
459 | }
460 | ]
461 | }
462 | ],
463 | "dnsPolicy": "ClusterFirst",
464 | "enableServiceLinks": true,
465 | "hostname": "keycloak-1",
466 | "imagePullSecrets": [
467 | {
468 | "name": "default-dockercfg-gm7sc"
469 | }
470 | ],
471 | "nodeName": "crc-vsqrt-master-0",
472 | "priority": 0,
473 | "restartPolicy": "Always",
474 | "schedulerName": "default-scheduler",
475 | "securityContext": {
476 | "fsGroup": 1000470000,
477 | "seLinuxOptions": {
478 | "level": "s0:c22,c4"
479 | }
480 | },
481 | "serviceAccount": "default",
482 | "serviceAccountName": "default",
483 | "terminationGracePeriodSeconds": 30,
484 | "tolerations": [
485 | {
486 | "effect": "NoExecute",
487 | "key": "node.kubernetes.io/unreachable",
488 | "operator": "Exists",
489 | "tolerationSeconds": 300
490 | },
491 | {
492 | "effect": "NoExecute",
493 | "key": "node.kubernetes.io/not-ready",
494 | "operator": "Exists",
495 | "tolerationSeconds": 300
496 | }
497 | ],
498 | "volumes": [
499 | {
500 | "name": "sso-x509-https-secret",
501 | "secret": {
502 | "defaultMode": 420,
503 | "optional": true,
504 | "secretName": "sso-x509-https-secret"
505 | }
506 | },
507 | {
508 | "name": "default-token-kv98v",
509 | "secret": {
510 | "defaultMode": 420,
511 | "secretName": "default-token-kv98v"
512 | }
513 | }
514 | ]
515 | },
516 | "status": {
517 | "conditions": [
518 | {
519 | "lastProbeTime": null,
520 | "lastTransitionTime": "2019-10-11T06:26:04Z",
521 | "status": "True",
522 | "type": "Initialized"
523 | },
524 | {
525 | "lastProbeTime": null,
526 | "lastTransitionTime": "2019-10-11T06:26:51Z",
527 | "status": "True",
528 | "type": "Ready"
529 | },
530 | {
531 | "lastProbeTime": null,
532 | "lastTransitionTime": "2019-10-11T06:26:51Z",
533 | "status": "True",
534 | "type": "ContainersReady"
535 | },
536 | {
537 | "lastProbeTime": null,
538 | "lastTransitionTime": "2019-10-11T06:26:03Z",
539 | "status": "True",
540 | "type": "PodScheduled"
541 | }
542 | ],
543 | "containerStatuses": [
544 | {
545 | "containerID": "cri-o://90c1daf447b9373e52ebf401f892b529a0fd740508a5ba9ec8d365267ece311f",
546 | "image": "registry.access.redhat.com/redhat-sso-7/sso73-openshift:1.0",
547 | "imageID": "registry.access.redhat.com/redhat-sso-7/sso73-openshift@sha256:35740d1dbebbb4dc39ea9ce4736d5cc54675a984b1ec0f9bef67eb48e93ffe2d",
548 | "lastState": {},
549 | "name": "keycloak",
550 | "ready": true,
551 | "restartCount": 0,
552 | "state": {
553 | "running": {
554 | "startedAt": "2019-10-11T06:26:12Z"
555 | }
556 | }
557 | }
558 | ],
559 | "hostIP": "192.168.130.11",
560 | "phase": "Running",
561 | "podIP": "10.128.0.234",
562 | "qosClass": "BestEffort",
563 | "startTime": "2019-10-11T06:26:04Z"
564 | }
565 | },
566 | {
567 | "apiVersion": "v1",
568 | "kind": "Pod",
569 | "metadata": {
570 | "annotations": {
571 | "k8s.v1.cni.cncf.io/networks-status": "[{\n \"name\": \"openshift-sdn\",\n \"interface\": \"eth0\",\n \"ips\": [\n \"10.128.0.237\"\n ],\n \"default\": true,\n \"dns\": {}\n}]",
572 | "openshift.io/scc": "restricted"
573 | },
574 | "creationTimestamp": "2019-10-11T06:51:40Z",
575 | "generateName": "keycloak-",
576 | "labels": {
577 | "application": "keycloak",
578 | "component": "keycloak",
579 | "controller-revision-hash": "keycloak-86d5dbd654",
580 | "statefulset.kubernetes.io/pod-name": "keycloak-2"
581 | },
582 | "name": "keycloak-2",
583 | "namespace": "keycloak",
584 | "ownerReferences": [
585 | {
586 | "apiVersion": "apps/v1",
587 | "blockOwnerDeletion": true,
588 | "controller": true,
589 | "kind": "StatefulSet",
590 | "name": "keycloak",
591 | "uid": "d6e308ff-eb37-11e9-ba11-52fdfc072182"
592 | }
593 | ],
594 | "resourceVersion": "249935",
595 | "selfLink": "/api/v1/namespaces/keycloak/pods/keycloak-2",
596 | "uid": "941c535c-ebf3-11e9-8261-52fdfc072182"
597 | },
598 | "spec": {
599 | "containers": [
600 | {
601 | "env": [
602 | {
603 | "name": "DB_SERVICE_PREFIX_MAPPING",
604 | "value": "keycloak-postgresql=DB"
605 | },
606 | {
607 | "name": "TEST",
608 | "value": "test"
609 | },
610 | {
611 | "name": "TX_DATABASE_PREFIX_MAPPING",
612 | "value": "keycloak-postgresql=DB"
613 | },
614 | {
615 | "name": "DB_JNDI",
616 | "value": "java:jboss/datasources/KeycloakDS"
617 | },
618 | {
619 | "name": "DB_SCHEMA",
620 | "value": "public"
621 | },
622 | {
623 | "name": "DB_USERNAME",
624 | "valueFrom": {
625 | "secretKeyRef": {
626 | "key": "user",
627 | "name": "keycloak-db-secret"
628 | }
629 | }
630 | },
631 | {
632 | "name": "DB_PASSWORD",
633 | "valueFrom": {
634 | "secretKeyRef": {
635 | "key": "password",
636 | "name": "keycloak-db-secret"
637 | }
638 | }
639 | },
640 | {
641 | "name": "DB_DATABASE",
642 | "value": "root"
643 | },
644 | {
645 | "name": "JGROUPS_PING_PROTOCOL",
646 | "value": "dns.DNS_PING"
647 | },
648 | {
649 | "name": "OPENSHIFT_DNS_PING_SERVICE_NAME",
650 | "value": "keycloak-discovery.keycloak.svc.cluster.local"
651 | },
652 | {
653 | "name": "SSO_ADMIN_USERNAME",
654 | "valueFrom": {
655 | "secretKeyRef": {
656 | "key": "ADMIN_USERNAME",
657 | "name": "credential-example-keycloak"
658 | }
659 | }
660 | },
661 | {
662 | "name": "SSO_ADMIN_PASSWORD",
663 | "valueFrom": {
664 | "secretKeyRef": {
665 | "key": "ADMIN_PASSWORD",
666 | "name": "credential-example-keycloak"
667 | }
668 | }
669 | }
670 | ],
671 | "image": "registry.access.redhat.com/redhat-sso-7/sso73-openshift:1.0",
672 | "imagePullPolicy": "IfNotPresent",
673 | "livenessProbe": {
674 | "failureThreshold": 3,
675 | "httpGet": {
676 | "path": "/auth/realms/master",
677 | "port": 8080,
678 | "scheme": "HTTP"
679 | },
680 | "initialDelaySeconds": 60,
681 | "periodSeconds": 10,
682 | "successThreshold": 1,
683 | "timeoutSeconds": 1
684 | },
685 | "name": "keycloak",
686 | "ports": [
687 | {
688 | "containerPort": 8443,
689 | "protocol": "TCP"
690 | },
691 | {
692 | "containerPort": 8080,
693 | "protocol": "TCP"
694 | },
695 | {
696 | "containerPort": 9990,
697 | "protocol": "TCP"
698 | },
699 | {
700 | "containerPort": 8778,
701 | "protocol": "TCP"
702 | }
703 | ],
704 | "readinessProbe": {
705 | "failureThreshold": 3,
706 | "httpGet": {
707 | "path": "/auth/realms/master",
708 | "port": 8080,
709 | "scheme": "HTTP"
710 | },
711 | "initialDelaySeconds": 10,
712 | "periodSeconds": 10,
713 | "successThreshold": 1,
714 | "timeoutSeconds": 1
715 | },
716 | "resources": {},
717 | "securityContext": {
718 | "capabilities": {
719 | "drop": [
720 | "KILL",
721 | "MKNOD",
722 | "SETGID",
723 | "SETUID"
724 | ]
725 | },
726 | "runAsUser": 1000470000
727 | },
728 | "terminationMessagePath": "/dev/termination-log",
729 | "terminationMessagePolicy": "File",
730 | "volumeMounts": [
731 | {
732 | "mountPath": "/etc/x509/https",
733 | "name": "sso-x509-https-secret"
734 | },
735 | {
736 | "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
737 | "name": "default-token-kv98v",
738 | "readOnly": true
739 | }
740 | ]
741 | }
742 | ],
743 | "dnsPolicy": "ClusterFirst",
744 | "enableServiceLinks": true,
745 | "hostname": "keycloak-2",
746 | "imagePullSecrets": [
747 | {
748 | "name": "default-dockercfg-gm7sc"
749 | }
750 | ],
751 | "nodeName": "crc-vsqrt-master-0",
752 | "priority": 0,
753 | "restartPolicy": "Always",
754 | "schedulerName": "default-scheduler",
755 | "securityContext": {
756 | "fsGroup": 1000470000,
757 | "seLinuxOptions": {
758 | "level": "s0:c22,c4"
759 | }
760 | },
761 | "serviceAccount": "default",
762 | "serviceAccountName": "default",
763 | "terminationGracePeriodSeconds": 30,
764 | "tolerations": [
765 | {
766 | "effect": "NoExecute",
767 | "key": "node.kubernetes.io/not-ready",
768 | "operator": "Exists",
769 | "tolerationSeconds": 300
770 | },
771 | {
772 | "effect": "NoExecute",
773 | "key": "node.kubernetes.io/unreachable",
774 | "operator": "Exists",
775 | "tolerationSeconds": 300
776 | }
777 | ],
778 | "volumes": [
779 | {
780 | "name": "sso-x509-https-secret",
781 | "secret": {
782 | "defaultMode": 420,
783 | "optional": true,
784 | "secretName": "sso-x509-https-secret"
785 | }
786 | },
787 | {
788 | "name": "default-token-kv98v",
789 | "secret": {
790 | "defaultMode": 420,
791 | "secretName": "default-token-kv98v"
792 | }
793 | }
794 | ]
795 | },
796 | "status": {
797 | "conditions": [
798 | {
799 | "lastProbeTime": null,
800 | "lastTransitionTime": "2019-10-11T06:51:40Z",
801 | "status": "True",
802 | "type": "Initialized"
803 | },
804 | {
805 | "lastProbeTime": null,
806 | "lastTransitionTime": "2019-10-11T06:52:47Z",
807 | "status": "True",
808 | "type": "Ready"
809 | },
810 | {
811 | "lastProbeTime": null,
812 | "lastTransitionTime": "2019-10-11T06:52:47Z",
813 | "status": "True",
814 | "type": "ContainersReady"
815 | },
816 | {
817 | "lastProbeTime": null,
818 | "lastTransitionTime": "2019-10-11T06:51:40Z",
819 | "status": "True",
820 | "type": "PodScheduled"
821 | }
822 | ],
823 | "containerStatuses": [
824 | {
825 | "containerID": "cri-o://b2a41f7f247d5b8eafdf0540df8c501b38cdafc27e136738788406dbf1f2d6c5",
826 | "image": "registry.access.redhat.com/redhat-sso-7/sso73-openshift:1.0",
827 | "imageID": "registry.access.redhat.com/redhat-sso-7/sso73-openshift@sha256:35740d1dbebbb4dc39ea9ce4736d5cc54675a984b1ec0f9bef67eb48e93ffe2d",
828 | "lastState": {},
829 | "name": "keycloak",
830 | "ready": true,
831 | "restartCount": 0,
832 | "state": {
833 | "running": {
834 | "startedAt": "2019-10-11T06:51:48Z"
835 | }
836 | }
837 | }
838 | ],
839 | "hostIP": "192.168.130.11",
840 | "phase": "Running",
841 | "podIP": "10.128.0.237",
842 | "qosClass": "BestEffort",
843 | "startTime": "2019-10-11T06:51:40Z"
844 | }
845 | },
846 | {
847 | "apiVersion": "v1",
848 | "kind": "Pod",
849 | "metadata": {
850 | "annotations": {
851 | "k8s.v1.cni.cncf.io/networks-status": "[{\n \"name\": \"openshift-sdn\",\n \"interface\": \"eth0\",\n \"ips\": [\n \"10.128.0.220\"\n ],\n \"default\": true,\n \"dns\": {}\n}]",
852 | "openshift.io/scc": "restricted"
853 | },
854 | "creationTimestamp": "2019-10-10T08:27:47Z",
855 | "generateName": "keycloak-postgresql-666b764458-",
856 | "labels": {
857 | "application": "keycloak",
858 | "component": "database",
859 | "pod-template-hash": "666b764458"
860 | },
861 | "name": "keycloak-postgresql-666b764458-tv6pk",
862 | "namespace": "keycloak",
863 | "ownerReferences": [
864 | {
865 | "apiVersion": "apps/v1",
866 | "blockOwnerDeletion": true,
867 | "controller": true,
868 | "kind": "ReplicaSet",
869 | "name": "keycloak-postgresql-666b764458",
870 | "uid": "d6cf7e74-eb37-11e9-ba11-52fdfc072182"
871 | }
872 | ],
873 | "resourceVersion": "239070",
874 | "selfLink": "/api/v1/namespaces/keycloak/pods/keycloak-postgresql-666b764458-tv6pk",
875 | "uid": "d6d53608-eb37-11e9-ba11-52fdfc072182"
876 | },
877 | "spec": {
878 | "containers": [
879 | {
880 | "env": [
881 | {
882 | "name": "POSTGRES_USER",
883 | "valueFrom": {
884 | "secretKeyRef": {
885 | "key": "user",
886 | "name": "keycloak-db-secret"
887 | }
888 | }
889 | },
890 | {
891 | "name": "PGUSER",
892 | "valueFrom": {
893 | "secretKeyRef": {
894 | "key": "user",
895 | "name": "keycloak-db-secret"
896 | }
897 | }
898 | },
899 | {
900 | "name": "POSTGRES_PASSWORD",
901 | "valueFrom": {
902 | "secretKeyRef": {
903 | "key": "password",
904 | "name": "keycloak-db-secret"
905 | }
906 | }
907 | },
908 | {
909 | "name": "POSTGRES_DB",
910 | "value": "root"
911 | },
912 | {
913 | "name": "PGDATA",
914 | "value": "/var/lib/postgresql/data/pgdata"
915 | }
916 | ],
917 | "image": "postgres:9.5",
918 | "imagePullPolicy": "IfNotPresent",
919 | "livenessProbe": {
920 | "failureThreshold": 3,
921 | "initialDelaySeconds": 30,
922 | "periodSeconds": 10,
923 | "successThreshold": 1,
924 | "tcpSocket": {
925 | "port": 5432
926 | },
927 | "timeoutSeconds": 1
928 | },
929 | "name": "keycloak-postgresql",
930 | "ports": [
931 | {
932 | "containerPort": 5432,
933 | "protocol": "TCP"
934 | }
935 | ],
936 | "readinessProbe": {
937 | "exec": {
938 | "command": [
939 | "/bin/sh",
940 | "-c",
941 | "psql -h 127.0.0.1 -U $POSTGRES_USER -q -d $POSTGRES_DB -c 'SELECT 1'"
942 | ]
943 | },
944 | "failureThreshold": 3,
945 | "initialDelaySeconds": 5,
946 | "periodSeconds": 10,
947 | "successThreshold": 1,
948 | "timeoutSeconds": 1
949 | },
950 | "resources": {},
951 | "securityContext": {
952 | "capabilities": {
953 | "drop": [
954 | "KILL",
955 | "MKNOD",
956 | "SETGID",
957 | "SETUID"
958 | ]
959 | },
960 | "runAsUser": 1000470000
961 | },
962 | "terminationMessagePath": "/dev/termination-log",
963 | "terminationMessagePolicy": "File",
964 | "volumeMounts": [
965 | {
966 | "mountPath": "/var/lib/pgsql/data",
967 | "name": "keycloak-postgresql-claim"
968 | },
969 | {
970 | "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount",
971 | "name": "default-token-kv98v",
972 | "readOnly": true
973 | }
974 | ]
975 | }
976 | ],
977 | "dnsPolicy": "ClusterFirst",
978 | "enableServiceLinks": true,
979 | "imagePullSecrets": [
980 | {
981 | "name": "default-dockercfg-gm7sc"
982 | }
983 | ],
984 | "nodeName": "crc-vsqrt-master-0",
985 | "priority": 0,
986 | "restartPolicy": "Always",
987 | "schedulerName": "default-scheduler",
988 | "securityContext": {
989 | "fsGroup": 1000470000,
990 | "seLinuxOptions": {
991 | "level": "s0:c22,c4"
992 | }
993 | },
994 | "serviceAccount": "default",
995 | "serviceAccountName": "default",
996 | "terminationGracePeriodSeconds": 30,
997 | "tolerations": [
998 | {
999 | "effect": "NoExecute",
1000 | "key": "node.kubernetes.io/not-ready",
1001 | "operator": "Exists",
1002 | "tolerationSeconds": 300
1003 | },
1004 | {
1005 | "effect": "NoExecute",
1006 | "key": "node.kubernetes.io/unreachable",
1007 | "operator": "Exists",
1008 | "tolerationSeconds": 300
1009 | }
1010 | ],
1011 | "volumes": [
1012 | {
1013 | "name": "keycloak-postgresql-claim",
1014 | "persistentVolumeClaim": {
1015 | "claimName": "keycloak-postgresql-claim"
1016 | }
1017 | },
1018 | {
1019 | "name": "default-token-kv98v",
1020 | "secret": {
1021 | "defaultMode": 420,
1022 | "secretName": "default-token-kv98v"
1023 | }
1024 | }
1025 | ]
1026 | },
1027 | "status": {
1028 | "conditions": [
1029 | {
1030 | "lastProbeTime": null,
1031 | "lastTransitionTime": "2019-10-10T08:27:47Z",
1032 | "status": "True",
1033 | "type": "Initialized"
1034 | },
1035 | {
1036 | "lastProbeTime": null,
1037 | "lastTransitionTime": "2019-10-11T06:02:48Z",
1038 | "status": "True",
1039 | "type": "Ready"
1040 | },
1041 | {
1042 | "lastProbeTime": null,
1043 | "lastTransitionTime": "2019-10-11T06:02:48Z",
1044 | "status": "True",
1045 | "type": "ContainersReady"
1046 | },
1047 | {
1048 | "lastProbeTime": null,
1049 | "lastTransitionTime": "2019-10-10T08:27:47Z",
1050 | "status": "True",
1051 | "type": "PodScheduled"
1052 | }
1053 | ],
1054 | "containerStatuses": [
1055 | {
1056 | "containerID": "cri-o://81a311d85b6f408cbae534e90c6fa12d074ea1cd742e0a59c4ca1cdf897ec6e7",
1057 | "image": "docker.io/library/postgres:9.5",
1058 | "imageID": "docker.io/library/postgres@sha256:57b963715ad4ca28481c5e9ab9acb769cc3e3868a9d4389681ebc7260a45e68c",
1059 | "lastState": {
1060 | "terminated": {
1061 | "containerID": "cri-o://1c7cf65c299a7a048c4501df40cfcb9b810f81e30dddd8bcab92ce6163fa6f2b",
1062 | "exitCode": 255,
1063 | "finishedAt": "2019-10-11T06:01:43Z",
1064 | "reason": "Error",
1065 | "startedAt": "2019-10-10T08:28:44Z"
1066 | }
1067 | },
1068 | "name": "keycloak-postgresql",
1069 | "ready": true,
1070 | "restartCount": 1,
1071 | "state": {
1072 | "running": {
1073 | "startedAt": "2019-10-11T06:02:18Z"
1074 | }
1075 | }
1076 | }
1077 | ],
1078 | "hostIP": "192.168.130.11",
1079 | "phase": "Running",
1080 | "podIP": "10.128.0.220",
1081 | "qosClass": "BestEffort",
1082 | "startTime": "2019-10-10T08:27:47Z"
1083 | }
1084 | }
1085 | ],
1086 | "kind": "List",
1087 | "metadata": {
1088 | "resourceVersion": "",
1089 | "selfLink": ""
1090 | }
1091 | }
1092 |
--------------------------------------------------------------------------------