Import k8s client deps, support inject k8s API server config

Change-Id: Iaf246a06462b8a878e93ef3f98da399c3600b129
This commit is contained in:
Jian Li 2019-02-12 00:31:35 +09:00
parent ec0f7483c3
commit 3defa842eb
28 changed files with 2301 additions and 20 deletions

View File

@ -2,6 +2,8 @@ BUNDLES = [
"//apps/k8s-networking/api:onos-apps-k8s-networking-api",
"//apps/k8s-networking/app:onos-apps-k8s-networking-app",
"@commons_net//jar",
"@k8s_client//jar",
"@k8s_model//jar",
]
onos_app(

View File

@ -5,6 +5,8 @@ COMPILE_DEPS = CORE_DEPS + JACKSON + KRYO + CLI + REST + [
"//apps/k8s-node/api:onos-apps-k8s-node-api",
"//apps/k8s-networking/api:onos-apps-k8s-networking-api",
"@commons_net//jar",
"@k8s_client//jar",
"@k8s_model//jar",
]
TEST_DEPS = TEST_ADAPTERS + TEST_REST + [

View File

@ -0,0 +1,202 @@
/*
* Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.k8snode.api;
import com.google.common.base.MoreObjects;
import org.onlab.packet.IpAddress;
import java.util.Objects;
import static com.google.common.base.Preconditions.checkArgument;
import static org.onosproject.k8snode.api.K8sApiConfig.Scheme.HTTPS;
/**
* Default implementation of kubernetes API configuration.
*/
public final class DefaultK8sApiConfig implements K8sApiConfig {
private static final String NOT_NULL_MSG = "API Config % cannot be null";
private final Scheme scheme;
private final IpAddress ipAddress;
private final int port;
private final String token;
private final String caCertData;
private final String clientCertData;
private final String clientKeyData;
private DefaultK8sApiConfig(Scheme scheme, IpAddress ipAddress, int port,
String token, String caCertData,
String clientCertData, String clientKeyData) {
this.scheme = scheme;
this.ipAddress = ipAddress;
this.port = port;
this.token = token;
this.caCertData = caCertData;
this.clientCertData = clientCertData;
this.clientKeyData = clientKeyData;
}
@Override
public Scheme scheme() {
return scheme;
}
@Override
public IpAddress ipAddress() {
return ipAddress;
}
@Override
public int port() {
return port;
}
@Override
public String token() {
return token;
}
@Override
public String caCertData() {
return caCertData;
}
@Override
public String clientCertData() {
return clientCertData;
}
@Override
public String clientKeyData() {
return clientKeyData;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DefaultK8sApiConfig that = (DefaultK8sApiConfig) o;
return port == that.port &&
scheme == that.scheme &&
ipAddress.equals(that.ipAddress) &&
token.equals(that.token) &&
caCertData.equals(that.caCertData) &&
clientCertData.equals(that.clientCertData) &&
clientKeyData.equals(that.clientKeyData);
}
@Override
public int hashCode() {
return Objects.hash(scheme, ipAddress, port, token, caCertData,
clientCertData, clientKeyData);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("scheme", scheme)
.add("ipAddress", ipAddress)
.add("port", port)
.add("token", token)
.add("caCertData", caCertData)
.add("clientCertData", clientCertData)
.add("clientKeyData", clientKeyData)
.toString();
}
/**
* Returns new builder instance.
*
* @return kubernetes API server config builder
*/
public static Builder builder() {
return new Builder();
}
public static final class Builder implements K8sApiConfig.Builder {
private Scheme scheme;
private IpAddress ipAddress;
private int port;
private String token;
private String caCertData;
private String clientCertData;
private String clientKeyData;
@Override
public K8sApiConfig build() {
checkArgument(scheme != null, NOT_NULL_MSG, "scheme");
checkArgument(ipAddress != null, NOT_NULL_MSG, "ipAddress");
if (scheme == HTTPS) {
checkArgument(token != null, NOT_NULL_MSG, "token");
checkArgument(caCertData != null, NOT_NULL_MSG, "caCertData");
checkArgument(clientCertData != null, NOT_NULL_MSG, "clientCertData");
checkArgument(clientKeyData != null, NOT_NULL_MSG, "clientKeyData");
}
return new DefaultK8sApiConfig(scheme, ipAddress, port, token,
caCertData, clientCertData, clientKeyData);
}
@Override
public Builder scheme(Scheme scheme) {
this.scheme = scheme;
return this;
}
@Override
public Builder ipAddress(IpAddress ipAddress) {
this.ipAddress = ipAddress;
return this;
}
@Override
public Builder port(int port) {
this.port = port;
return this;
}
@Override
public Builder token(String token) {
this.token = token;
return this;
}
@Override
public Builder caCertData(String caCertData) {
this.caCertData = caCertData;
return this;
}
@Override
public Builder clientCertData(String clientCertData) {
this.clientCertData = clientCertData;
return this;
}
@Override
public Builder clientKeyData(String clientKeyData) {
this.clientKeyData = clientKeyData;
return this;
}
}
}

View File

@ -59,7 +59,8 @@ public class DefaultK8sNode implements K8sNode {
* @param state node state
*/
protected DefaultK8sNode(String hostname, Type type, DeviceId intgBridge,
IpAddress managementIp, IpAddress dataIp, K8sNodeState state) {
IpAddress managementIp, IpAddress dataIp,
K8sNodeState state) {
this.hostname = hostname;
this.type = type;
this.intgBridge = intgBridge;
@ -222,6 +223,7 @@ public class DefaultK8sNode implements K8sNode {
private IpAddress managementIp;
private IpAddress dataIp;
private K8sNodeState state;
private K8sApiConfig apiConfig;
// private constructor not intended to use from external
private Builder() {

View File

@ -0,0 +1,157 @@
/*
* Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.k8snode.api;
import org.onlab.packet.IpAddress;
/**
* Representation of configuration used in kubernetes API server.
*/
public interface K8sApiConfig {
/**
* Lists of authentication schemes.
*/
enum Scheme {
/**
* Signifies that this is a HTTP authentication scheme.
*/
HTTP,
/**
* Signifies that this is a HTTPS authentication scheme.
*/
HTTPS,
}
/**
* Returns the authentication scheme.
*
* @return authentication scheme
*/
Scheme scheme();
/**
* Returns the IP address of kubernetes API server.
*
* @return IP address of kubernetes API server
*/
IpAddress ipAddress();
/**
* Returns the port number of kubernetes API server.
*
* @return port number of kubernetes API server
*/
int port();
/**
* Returns the token used for authenticating to API server.
*
* @return token value
*/
String token();
/**
* Returns the CA certificate data.
*
* @return CA certificate data
*/
String caCertData();
/**
* Returns the client certificate data.
*
* @return client certificate data
*/
String clientCertData();
/**
* Returns the client key data.
*
* @return client key data
*/
String clientKeyData();
/**
* Builder of new API config entity.
*/
interface Builder {
/**
* Builds an immutable kubernetes API config instance.
*
* @return kubernetes API config instance
*/
K8sApiConfig build();
/**
* Returns kubernetes API server config builder with supplied scheme.
*
* @param scheme scheme of authentication
* @return kubernetes API config builder
*/
Builder scheme(Scheme scheme);
/**
* Returns kubernetes API server config builder with supplied IP address.
*
* @param ipAddress IP address of kubernetes API server
* @return kubernetes API config builder
*/
Builder ipAddress(IpAddress ipAddress);
/**
* Returns kubernetes API server config builder with supplied port number.
*
* @param port port number of kubernetes API server
* @return kubernetes API config builder
*/
Builder port(int port);
/**
* Returns kubernetes API server config builder with supplied token.
*
* @param token token for authentication
* @return kubernetes API config builder
*/
Builder token(String token);
/**
* Returns kubernetes API server config builder with supplied CA certificate data.
*
* @param caCertData CA certificate data
* @return kubernetes API config builder
*/
Builder caCertData(String caCertData);
/**
* Returns kubernetes API server config builder with supplied client certificate data.
*
* @param clientCertData client certificate data
* @return kubernetes API config builder
*/
Builder clientCertData(String clientCertData);
/**
* Returns kubernetes API server config builder with supplied client key data.
*
* @param clientKeyData client key data
* @return kubernetes API config builder
*/
Builder clientKeyData(String clientKeyData);
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.k8snode.api;
import org.onlab.packet.IpAddress;
/**
* Service for administering inventory of kubernetes API configs.
*/
public interface K8sApiConfigAdminService extends K8sApiConfigService {
/**
* Creates an API config.
*
* @param config kubernetes API server config
*/
void createApiConfig(K8sApiConfig config);
/**
* Updates the API config.
*
* @param config kubernetes API server config
*/
void updateApiConfig(K8sApiConfig config);
/**
* Removes the API config.
*
* @param endpoint kubernetes API endpoint
* @return removed kubernetes API server config; null if no config
* associated with the endpoint
*/
K8sApiConfig removeApiConfig(String endpoint);
/**
* Removes the kubernetes API config with the given scheme, IP and port.
*
* @param scheme scheme (HTTP/HTTPS)
* @param ipAddress IP address of API server
* @param port port number of API server
* @return removed kubernetes API server config; null if no config
* associated with the scheme, IP and port
*/
K8sApiConfig removeApiConfig(K8sApiConfig.Scheme scheme, IpAddress ipAddress, int port);
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.k8snode.api;
import org.onosproject.event.AbstractEvent;
/**
* Describes kubernetes API server config event.
*/
public class K8sApiConfigEvent extends AbstractEvent<K8sApiConfigEvent.Type, K8sApiConfig> {
/**
* Lists of kubernetes API server config event types.
*/
public enum Type {
/**
* Signifies that API config is created.
*/
K8S_API_CONFIG_CREATED,
/**
* Signifies that API config is updated.
*/
K8S_API_CONFIG_UPDATED,
/**
* Signifies that API config is removed.
*/
K8S_API_CONFIG_REMOVED,
}
/**
* Creates an event with the given type and node.
*
* @param type event type
* @param subject kubernetes API config
*/
public K8sApiConfigEvent(Type type, K8sApiConfig subject) {
super(type, subject);
}
}

View File

@ -0,0 +1,24 @@
/*
* Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.k8snode.api;
import org.onosproject.event.EventListener;
/**
* Listener for kubernetes API config event.
*/
public interface K8sApiConfigListener extends EventListener<K8sApiConfigEvent> {
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.k8snode.api;
import org.onlab.packet.IpAddress;
import org.onosproject.event.ListenerService;
import org.onosproject.k8snode.api.K8sApiConfig.Scheme;
import java.util.Set;
/**
* Service for interfacing with the inventory of kubernetes API server config.
*/
public interface K8sApiConfigService
extends ListenerService<K8sApiConfigEvent, K8sApiConfigListener> {
String APP_ID = "org.onosproject.k8snode";
/**
* Returns all registered API configs.
*
* @return set of kubernetes API configs
*/
Set<K8sApiConfig> apiConfigs();
/**
* Returns the API config with the specified endpoint.
*
* @param endpoint endpoint
* @return kubernetes API config
*/
K8sApiConfig apiConfig(String endpoint);
/**
* Returns the API config with the specified scheme, IP and port.
*
* @param scheme scheme (HTTP/HTTPS)
* @param ipAddress IP address of API server
* @param port port number of API server
* @return kubernetes API config
*/
K8sApiConfig apiConfig(Scheme scheme, IpAddress ipAddress, int port);
}

View File

@ -0,0 +1,89 @@
/*
* Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.k8snode.api;
import org.onlab.packet.IpAddress;
import org.onosproject.k8snode.api.K8sApiConfig.Scheme;
import org.onosproject.store.Store;
import java.util.Set;
/**
* Manages inventory of kubernetes API config; not intended for direct use.
*/
public interface K8sApiConfigStore
extends Store<K8sApiConfigEvent, K8sApiConfigStoreDelegate> {
/**
* Creates a API config.
*
* @param config kubernetes API server config
*/
void createApiConfig(K8sApiConfig config);
/**
* Updates the API config.
*
* @param config kubernetes API server config
*/
void updateApiConfig(K8sApiConfig config);
/**
* Removes the kubernetes API config with the given endpoint.
* Endpoint comprises of scheme (HTTP), IP address and port
*
* @param endpoint kubernetes API endpoint
* @return removed kubernetes API server config; null if no config
* associated with the endpoint
*/
K8sApiConfig removeApiConfig(String endpoint);
/**
* Removes the kubernetes API config with the given scheme, IP and port.
*
* @param scheme scheme (HTTP/HTTPS)
* @param ipAddress IP address of API server
* @param port port number of API server
* @return removed kubernetes API server config; null if no config
* associated with the scheme, IP and port
*/
K8sApiConfig removeApiConfig(Scheme scheme, IpAddress ipAddress, int port);
/**
* Returns all registered kubernetes API configs.
*
* @return set of kubernetes API configs
*/
Set<K8sApiConfig> apiConfigs();
/**
* Returns the API config with the specified endpoint.
*
* @param endpoint endpoint
* @return kubernetes API config
*/
K8sApiConfig apiConfig(String endpoint);
/**
* Returns the API config with the specified scheme, IP and port.
*
* @param scheme scheme (HTTP/HTTPS)
* @param ipAddress IP address of API server
* @param port port number of API server
* @return kubernetes API config
*/
K8sApiConfig apiConfig(Scheme scheme, IpAddress ipAddress, int port);
}

View File

@ -0,0 +1,24 @@
/*
* Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.k8snode.api;
import org.onosproject.store.StoreDelegate;
/**
* Kubernetes API server config store delegate.
*/
public interface K8sApiConfigStoreDelegate extends StoreDelegate<K8sApiConfigEvent> {
}

View File

@ -0,0 +1,128 @@
/*
* Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.k8snode.api;
import com.google.common.testing.EqualsTester;
import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.IpAddress;
import org.onosproject.k8snode.api.K8sApiConfig.Scheme;
import static junit.framework.TestCase.assertEquals;
import static org.onlab.junit.ImmutableClassChecker.assertThatClassIsImmutable;
import static org.onosproject.k8snode.api.K8sApiConfig.Scheme.HTTP;
import static org.onosproject.k8snode.api.K8sApiConfig.Scheme.HTTPS;
/**
* Unit tests for DefaultK8sApiConfig.
*/
public final class DefaultK8sApiConfigTest {
private static final Scheme SCHEME_1 = HTTP;
private static final Scheme SCHEME_2 = HTTPS;
private static final IpAddress IP_ADDRESS_1 = IpAddress.valueOf("192.168.0.200");
private static final IpAddress IP_ADDRESS_2 = IpAddress.valueOf("192.168.0.201");
private static final int PORT_1 = 6443;
private static final int PORT_2 = 443;
private static final String TOKEN_1 = "token1";
private static final String TOKEN_2 = "token2";
private static final String CA_CERT_DATA_1 = "caCertData1";
private static final String CA_CERT_DATA_2 = "caCertData2";
private static final String CLIENT_CERT_DATA_1 = "clientCertData1";
private static final String CLIENT_CERT_DATA_2 = "clientCertData2";
private static final String CLIENT_KEY_DATA_1 = "clientKeyData1";
private static final String CLIENT_KEY_DATA_2 = "clientKeyData2";
private K8sApiConfig config1;
private K8sApiConfig sameAsConfig1;
private K8sApiConfig config2;
/**
* Tests class immutability.
*/
@Test
public void testImmutability() {
assertThatClassIsImmutable(DefaultK8sApiConfig.class);
}
/**
* Initial setup for this unit test.
*/
@Before
public void setUp() {
config1 = DefaultK8sApiConfig.builder()
.scheme(SCHEME_1)
.ipAddress(IP_ADDRESS_1)
.port(PORT_1)
.token(TOKEN_1)
.caCertData(CA_CERT_DATA_1)
.clientCertData(CLIENT_CERT_DATA_1)
.clientKeyData(CLIENT_KEY_DATA_1)
.build();
sameAsConfig1 = DefaultK8sApiConfig.builder()
.scheme(SCHEME_1)
.ipAddress(IP_ADDRESS_1)
.port(PORT_1)
.token(TOKEN_1)
.caCertData(CA_CERT_DATA_1)
.clientCertData(CLIENT_CERT_DATA_1)
.clientKeyData(CLIENT_KEY_DATA_1)
.build();
config2 = DefaultK8sApiConfig.builder()
.scheme(SCHEME_2)
.ipAddress(IP_ADDRESS_2)
.port(PORT_2)
.token(TOKEN_2)
.caCertData(CA_CERT_DATA_2)
.clientCertData(CLIENT_CERT_DATA_2)
.clientKeyData(CLIENT_KEY_DATA_2)
.build();
}
/**
* Tests object equality.
*/
@Test
public void testEquality() {
new EqualsTester().addEqualityGroup(config1, sameAsConfig1)
.addEqualityGroup(config2)
.testEquals();
}
/**
* Test object construction.
*/
@Test
public void testConstruction() {
K8sApiConfig config = config1;
assertEquals(SCHEME_1, config.scheme());
assertEquals(IP_ADDRESS_1, config.ipAddress());
assertEquals(PORT_1, config.port());
assertEquals(TOKEN_1, config.token());
assertEquals(CA_CERT_DATA_1, config.caCertData());
assertEquals(CLIENT_CERT_DATA_1, config.clientCertData());
assertEquals(CLIENT_KEY_DATA_1, config.clientKeyData());
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.k8snode.cli;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.google.common.collect.Lists;
import org.apache.karaf.shell.api.action.Command;
import org.apache.karaf.shell.api.action.lifecycle.Service;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.k8snode.api.K8sApiConfig;
import org.onosproject.k8snode.api.K8sApiConfigService;
import java.util.Comparator;
import java.util.List;
import static org.onosproject.k8snode.util.K8sNodeUtil.prettyJson;
/**
* Lists all kubernetes API server configs registered to the service.
*/
@Service
@Command(scope = "onos", name = "k8s-api-configs",
description = "Lists all kubernetes API server configs registered to the service")
public class K8sApiConfigListCommand extends AbstractShellCommand {
private static final String FORMAT = "%-10s%-25s%-10s";
@Override
protected void doExecute() {
K8sApiConfigService configService = get(K8sApiConfigService.class);
List<K8sApiConfig> configs = Lists.newArrayList(configService.apiConfigs());
configs.sort(Comparator.comparing(K8sApiConfig::ipAddress));
if (outputJson()) {
print("%s", json(configs));
} else {
print(FORMAT, "Scheme", "IpAddress", "Port");
for (K8sApiConfig config : configs) {
print(FORMAT, config.scheme().name(),
config.ipAddress().toString(), config.port());
}
print("Total %s API configs", configService.apiConfigs().size());
}
}
private String json(List<K8sApiConfig> configs) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
for (K8sApiConfig config : configs) {
result.add(jsonForEntity(config, K8sApiConfig.class));
}
return prettyJson(mapper, result.toString());
}
}

View File

@ -0,0 +1,140 @@
/*
* Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.k8snode.codec;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.onlab.packet.IpAddress;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.k8snode.api.DefaultK8sApiConfig;
import org.onosproject.k8snode.api.K8sApiConfig;
import org.onosproject.k8snode.api.K8sApiConfig.Scheme;
import static org.onlab.util.Tools.nullIsIllegal;
import static org.onosproject.k8snode.api.K8sApiConfig.Scheme.HTTPS;
/**
* Kubernetes API server config codec used for serializing and de-serializing JSON string.
*/
public final class K8sApiConfigCodec extends JsonCodec<K8sApiConfig> {
private static final String SCHEME = "scheme";
private static final String IP_ADDRESS = "ipAddress";
private static final String PORT = "port";
private static final String TOKEN = "token";
private static final String CA_CERT_DATA = "caCertData";
private static final String CLIENT_CERT_DATA = "clientCertData";
private static final String CLIENT_KEY_DATA = "clientKeyData";
private static final String MISSING_MESSAGE = " is required in K8sApiConfig";
@Override
public ObjectNode encode(K8sApiConfig entity, CodecContext context) {
ObjectNode node = context.mapper().createObjectNode()
.put(SCHEME, entity.scheme().name())
.put(IP_ADDRESS, entity.ipAddress().toString())
.put(PORT, entity.port());
if (entity.scheme() == HTTPS) {
node.put(TOKEN, entity.token())
.put(CA_CERT_DATA, entity.caCertData())
.put(CLIENT_CERT_DATA, entity.clientCertData())
.put(CLIENT_KEY_DATA, entity.clientKeyData());
} else {
if (entity.token() != null) {
node.put(TOKEN, entity.token());
}
if (entity.caCertData() != null) {
node.put(CA_CERT_DATA, entity.caCertData());
}
if (entity.clientCertData() != null) {
node.put(CLIENT_CERT_DATA, entity.clientCertData());
}
if (entity.clientKeyData() != null) {
node.put(CLIENT_KEY_DATA, entity.clientKeyData());
}
}
return node;
}
@Override
public K8sApiConfig decode(ObjectNode json, CodecContext context) {
if (json == null || !json.isObject()) {
return null;
}
Scheme scheme = Scheme.valueOf(nullIsIllegal(
json.get(SCHEME).asText(), SCHEME + MISSING_MESSAGE));
IpAddress ipAddress = IpAddress.valueOf(nullIsIllegal(
json.get(IP_ADDRESS).asText(), IP_ADDRESS + MISSING_MESSAGE));
int port = json.get(PORT).asInt();
K8sApiConfig.Builder builder = DefaultK8sApiConfig.builder()
.scheme(scheme)
.ipAddress(ipAddress)
.port(port);
JsonNode tokenJson = json.get(TOKEN);
JsonNode caCertDataJson = json.get(CA_CERT_DATA);
JsonNode clientCertDataJson = json.get(CLIENT_CERT_DATA);
JsonNode clientKeyDataJson = json.get(CLIENT_KEY_DATA);
String token = "";
String caCertData = "";
String clientCertData = "";
String clientKeyData = "";
if (scheme == HTTPS) {
token = nullIsIllegal(tokenJson.asText(),
TOKEN + MISSING_MESSAGE);
caCertData = nullIsIllegal(caCertDataJson.asText(),
CA_CERT_DATA + MISSING_MESSAGE);
clientCertData = nullIsIllegal(clientCertDataJson.asText(),
CLIENT_CERT_DATA + MISSING_MESSAGE);
clientKeyData = nullIsIllegal(clientKeyDataJson.asText(),
CLIENT_KEY_DATA + MISSING_MESSAGE);
} else {
if (tokenJson != null) {
token = tokenJson.asText();
}
if (caCertDataJson != null) {
caCertData = caCertDataJson.asText();
}
if (clientCertDataJson != null) {
clientCertData = clientCertDataJson.asText();
}
if (clientKeyDataJson != null) {
clientKeyData = clientKeyDataJson.asText();
}
}
return builder.token(token)
.caCertData(caCertData)
.clientCertData(clientCertData)
.clientKeyData(clientKeyData)
.build();
}
}

View File

@ -0,0 +1,198 @@
/*
* Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.k8snode.impl;
import com.google.common.collect.ImmutableSet;
import org.onlab.packet.IpAddress;
import org.onlab.util.KryoNamespace;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.k8snode.api.DefaultK8sApiConfig;
import org.onosproject.k8snode.api.K8sApiConfig;
import org.onosproject.k8snode.api.K8sApiConfigEvent;
import org.onosproject.k8snode.api.K8sApiConfigStore;
import org.onosproject.k8snode.api.K8sApiConfigStoreDelegate;
import org.onosproject.store.AbstractStore;
import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.ConsistentMap;
import org.onosproject.store.service.MapEvent;
import org.onosproject.store.service.MapEventListener;
import org.onosproject.store.service.Serializer;
import org.onosproject.store.service.StorageService;
import org.onosproject.store.service.Versioned;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.slf4j.Logger;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.k8snode.api.K8sApiConfigEvent.Type.K8S_API_CONFIG_CREATED;
import static org.onosproject.k8snode.api.K8sApiConfigEvent.Type.K8S_API_CONFIG_REMOVED;
import static org.onosproject.k8snode.api.K8sApiConfigEvent.Type.K8S_API_CONFIG_UPDATED;
import static org.onosproject.k8snode.util.K8sNodeUtil.endpoint;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Implementation of kubernetes API config store using consistent map.
*/
@Component(immediate = true, service = K8sApiConfigStore.class)
public class DistributedK8sApiConfigStore
extends AbstractStore<K8sApiConfigEvent, K8sApiConfigStoreDelegate>
implements K8sApiConfigStore {
private final Logger log = getLogger(getClass());
private static final String ERR_NOT_FOUND = " does not exist";
private static final String ERR_DUPLICATE = " already exists";
private static final String APP_ID = "org.onosproject.k8snode";
private static final KryoNamespace
SERIALIZER_K8S_API_CONFIG = KryoNamespace.newBuilder()
.register(KryoNamespaces.API)
.register(K8sApiConfig.class)
.register(DefaultK8sApiConfig.class)
.register(K8sApiConfig.Scheme.class)
.register(Collection.class)
.build();
@Reference(cardinality = ReferenceCardinality.MANDATORY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY)
protected StorageService storageService;
private final ExecutorService eventExecutor = newSingleThreadExecutor(
groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
private final MapEventListener<String, K8sApiConfig> apiConfigMapListener =
new K8sApiConfigMapListener();
private ConsistentMap<String, K8sApiConfig> apiConfigStore;
@Activate
protected void activate() {
ApplicationId appId = coreService.registerApplication(APP_ID);
apiConfigStore = storageService.<String, K8sApiConfig>consistentMapBuilder()
.withSerializer(Serializer.using(SERIALIZER_K8S_API_CONFIG))
.withName("k8s-apiconfig-store")
.withApplicationId(appId)
.build();
apiConfigStore.addListener(apiConfigMapListener);
log.info("Started");
}
@Deactivate
protected void deactivate() {
apiConfigStore.removeListener(apiConfigMapListener);
eventExecutor.shutdown();
log.info("Stopped");
}
@Override
public void createApiConfig(K8sApiConfig config) {
String key = endpoint(config);
apiConfigStore.compute(key, (endpoint, existing) -> {
final String error = key + ERR_DUPLICATE;
checkArgument(existing == null, error);
return config;
});
}
@Override
public void updateApiConfig(K8sApiConfig config) {
String key = endpoint(config);
apiConfigStore.compute(key, (endpoint, existing) -> {
final String error = key + ERR_NOT_FOUND;
checkArgument(existing != null, error);
return config;
});
}
@Override
public K8sApiConfig removeApiConfig(String endpoint) {
Versioned<K8sApiConfig> apiConfig = apiConfigStore.remove(endpoint);
if (apiConfig == null) {
final String error = endpoint + ERR_NOT_FOUND;
throw new IllegalArgumentException(error);
}
return apiConfig.value();
}
@Override
public K8sApiConfig removeApiConfig(K8sApiConfig.Scheme scheme,
IpAddress ipAddress, int port) {
String key = endpoint(scheme, ipAddress, port);
return removeApiConfig(key);
}
@Override
public Set<K8sApiConfig> apiConfigs() {
return ImmutableSet.copyOf(apiConfigStore.asJavaMap().values());
}
@Override
public K8sApiConfig apiConfig(String endpoint) {
return apiConfigStore.asJavaMap().get(endpoint);
}
@Override
public K8sApiConfig apiConfig(K8sApiConfig.Scheme scheme,
IpAddress ipAddress, int port) {
String key = endpoint(scheme, ipAddress, port);
return apiConfig(key);
}
private class K8sApiConfigMapListener
implements MapEventListener<String, K8sApiConfig> {
@Override
public void event(MapEvent<String, K8sApiConfig> event) {
switch (event.type()) {
case INSERT:
log.debug("Kubernetes API config created {}", event.newValue());
eventExecutor.execute(() ->
notifyDelegate(new K8sApiConfigEvent(
K8S_API_CONFIG_CREATED, event.newValue().value()
)));
break;
case UPDATE:
log.debug("Kubernetes API config updated {}", event.newValue());
eventExecutor.execute(() ->
notifyDelegate(new K8sApiConfigEvent(
K8S_API_CONFIG_UPDATED, event.newValue().value()
)));
break;
case REMOVE:
log.debug("Kubernetes API config removed {}", event.oldValue());
eventExecutor.execute(() ->
notifyDelegate(new K8sApiConfigEvent(
K8S_API_CONFIG_REMOVED, event.oldValue().value()
)));
break;
default:
// do nothing
break;
}
}
}
}

View File

@ -0,0 +1,167 @@
/*
* Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.k8snode.impl;
import com.google.common.base.Strings;
import org.onlab.packet.IpAddress;
import org.onosproject.cluster.ClusterService;
import org.onosproject.cluster.LeadershipService;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.event.ListenerRegistry;
import org.onosproject.k8snode.api.K8sApiConfig;
import org.onosproject.k8snode.api.K8sApiConfig.Scheme;
import org.onosproject.k8snode.api.K8sApiConfigAdminService;
import org.onosproject.k8snode.api.K8sApiConfigEvent;
import org.onosproject.k8snode.api.K8sApiConfigListener;
import org.onosproject.k8snode.api.K8sApiConfigService;
import org.onosproject.k8snode.api.K8sApiConfigStore;
import org.onosproject.k8snode.api.K8sApiConfigStoreDelegate;
import org.onosproject.store.service.StorageService;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.slf4j.Logger;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.k8snode.util.K8sNodeUtil.endpoint;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Service administering the inventory of kubernetes API configs.
*/
@Component(
immediate = true,
service = { K8sApiConfigService.class, K8sApiConfigAdminService.class }
)
public class K8sApiConfigManager
extends ListenerRegistry<K8sApiConfigEvent, K8sApiConfigListener>
implements K8sApiConfigService, K8sApiConfigAdminService {
private final Logger log = getLogger(getClass());
private static final String MSG_CONFIG = "Kubernetes API config %s %s";
private static final String MSG_CREATED = "created";
private static final String MSG_UPDATED = "updated";
private static final String MSG_REMOVED = "removed";
private static final String ERR_NULL_CONFIG = "Kubernetes API config cannot be null";
private static final String ERR_NULL_ENDPOINT = "Kubernetes API endpoint cannot be null";
@Reference(cardinality = ReferenceCardinality.MANDATORY)
protected K8sApiConfigStore configStore;
@Reference(cardinality = ReferenceCardinality.MANDATORY)
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY)
protected ClusterService clusterService;
@Reference(cardinality = ReferenceCardinality.MANDATORY)
protected LeadershipService leadershipService;
@Reference(cardinality = ReferenceCardinality.MANDATORY)
protected StorageService storageService;
private final ExecutorService eventExecutor = newSingleThreadExecutor(
groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
private final K8sApiConfigStoreDelegate delegate = new InternalApiConfigStoreDelegate();
private ApplicationId appId;
@Activate
protected void activate() {
appId = coreService.registerApplication(APP_ID);
configStore.setDelegate(delegate);
leadershipService.runForLeadership(appId.name());
log.info("Started");
}
@Deactivate
protected void deactivate() {
configStore.unsetDelegate(delegate);
leadershipService.withdraw(appId.name());
eventExecutor.shutdown();
log.info("Stopped");
}
@Override
public void createApiConfig(K8sApiConfig config) {
checkNotNull(config, ERR_NULL_CONFIG);
configStore.createApiConfig(config);
log.info(String.format(MSG_CONFIG, endpoint(config), MSG_CREATED));
}
@Override
public void updateApiConfig(K8sApiConfig config) {
checkNotNull(config, ERR_NULL_CONFIG);
configStore.updateApiConfig(config);
log.info(String.format(MSG_CONFIG, endpoint(config), MSG_UPDATED));
}
@Override
public K8sApiConfig removeApiConfig(String endpoint) {
checkArgument(!Strings.isNullOrEmpty(endpoint), ERR_NULL_ENDPOINT);
K8sApiConfig config = configStore.removeApiConfig(endpoint);
log.info(String.format(MSG_CONFIG, endpoint, MSG_REMOVED));
return config;
}
@Override
public K8sApiConfig removeApiConfig(Scheme scheme,
IpAddress ipAddress, int port) {
return removeApiConfig(endpoint(scheme, ipAddress, port));
}
@Override
public Set<K8sApiConfig> apiConfigs() {
return configStore.apiConfigs();
}
@Override
public K8sApiConfig apiConfig(String endpoint) {
return configStore.apiConfig(endpoint);
}
@Override
public K8sApiConfig apiConfig(Scheme scheme, IpAddress ipAddress, int port) {
return apiConfig(endpoint(scheme, ipAddress, port));
}
private class InternalApiConfigStoreDelegate implements K8sApiConfigStoreDelegate {
@Override
public void notify(K8sApiConfigEvent event) {
if (event != null) {
log.trace("send kubernetes API config event {}", event);
process(event);
}
}
}
}

View File

@ -17,6 +17,10 @@ package org.onosproject.k8snode.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Strings;
import org.apache.commons.lang.StringUtils;
import org.onlab.packet.IpAddress;
import org.onosproject.k8snode.api.K8sApiConfig;
import org.onosproject.k8snode.api.K8sApiConfig.Scheme;
import org.onosproject.k8snode.api.K8sNode;
import org.onosproject.net.Device;
import org.onosproject.net.behaviour.BridgeConfig;
@ -39,6 +43,9 @@ import static org.onlab.util.Tools.get;
public final class K8sNodeUtil {
private static final Logger log = LoggerFactory.getLogger(K8sNodeUtil.class);
private static final String COLON_SLASH = "://";
private static final String COLON = ":";
/**
* Prevents object installation from external.
*/
@ -146,4 +153,35 @@ public final class K8sNodeUtil {
}
return null;
}
/**
* Generates endpoint URL by referring to scheme, ipAddress and port.
*
* @param scheme scheme
* @param ipAddress IP address
* @param port port number
* @return generated endpoint URL
*/
public static String endpoint(Scheme scheme, IpAddress ipAddress, int port) {
StringBuilder endpoint = new StringBuilder();
String protocol = StringUtils.lowerCase(scheme.name());
endpoint.append(protocol);
endpoint.append(COLON_SLASH);
endpoint.append(ipAddress.toString());
endpoint.append(COLON);
endpoint.append(port);
return endpoint.toString();
}
/**
* Generates endpoint URL by referring to scheme, ipAddress and port.
*
* @param apiConfig kubernetes API config
* @return generated endpoint URL
*/
public static String endpoint(K8sApiConfig apiConfig) {
return endpoint(apiConfig.scheme(), apiConfig.ipAddress(), apiConfig.port());
}
}

View File

@ -16,7 +16,9 @@
package org.onosproject.k8snode.web;
import org.onosproject.codec.CodecService;
import org.onosproject.k8snode.api.K8sApiConfig;
import org.onosproject.k8snode.api.K8sNode;
import org.onosproject.k8snode.codec.K8sApiConfigCodec;
import org.onosproject.k8snode.codec.K8sNodeCodec;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
@ -42,6 +44,7 @@ public class K8sNodeCodecRegister {
protected void activate() {
codecService.registerCodec(K8sNode.class, new K8sNodeCodec());
codecService.registerCodec(K8sApiConfig.class, new K8sApiConfigCodec());
log.info("Started");
}
@ -50,6 +53,7 @@ public class K8sNodeCodecRegister {
protected void deactivate() {
codecService.unregisterCodec(K8sNode.class);
codecService.unregisterCodec(K8sApiConfig.class);
log.info("Stopped");
}

View File

@ -19,6 +19,8 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Sets;
import org.onosproject.k8snode.api.K8sApiConfig;
import org.onosproject.k8snode.api.K8sApiConfigAdminService;
import org.onosproject.k8snode.api.K8sNode;
import org.onosproject.k8snode.api.K8sNodeAdminService;
import org.onosproject.rest.AbstractWebResource;
@ -26,6 +28,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
@ -43,6 +46,7 @@ import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
import static javax.ws.rs.core.Response.created;
import static org.onlab.util.Tools.nullIsIllegal;
import static org.onlab.util.Tools.readTreeFromStream;
import static org.onosproject.k8snode.util.K8sNodeUtil.endpoint;
/**
* Handles REST API call of kubernetes node config.
@ -55,15 +59,18 @@ public class K8sNodeWebResource extends AbstractWebResource {
private static final String MESSAGE_NODE = "Received node %s request";
private static final String NODES = "nodes";
private static final String API_CONFIGS = "apiConfigs";
private static final String CREATE = "CREATE";
private static final String UPDATE = "UPDATE";
private static final String NODE_ID = "NODE_ID";
private static final String DELETE = "DELETE";
private static final String REMOVE = "REMOVE";
private static final String HOST_NAME = "hostname";
private static final String ENDPOINT = "endpoint";
private static final String ERROR_MESSAGE = " cannot be null";
private final K8sNodeAdminService adminService = get(K8sNodeAdminService.class);
private final K8sNodeAdminService nodeAdminService = get(K8sNodeAdminService.class);
private final K8sApiConfigAdminService configAdminService = get(K8sApiConfigAdminService.class);
@Context
private UriInfo uriInfo;
@ -77,15 +84,16 @@ public class K8sNodeWebResource extends AbstractWebResource {
* @onos.rsModel K8sNode
*/
@POST
@Path("node")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createNodes(InputStream input) {
log.trace(String.format(MESSAGE_NODE, CREATE));
readNodeConfiguration(input).forEach(node -> {
K8sNode existing = adminService.node(node.hostname());
K8sNode existing = nodeAdminService.node(node.hostname());
if (existing == null) {
adminService.createNode(node);
nodeAdminService.createNode(node);
}
});
@ -105,6 +113,7 @@ public class K8sNodeWebResource extends AbstractWebResource {
* @onos.rsModel K8sNode
*/
@PUT
@Path("node")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response updateNodes(InputStream input) {
@ -112,12 +121,12 @@ public class K8sNodeWebResource extends AbstractWebResource {
Set<K8sNode> nodes = readNodeConfiguration(input);
for (K8sNode node: nodes) {
K8sNode existing = adminService.node(node.hostname());
K8sNode existing = nodeAdminService.node(node.hostname());
if (existing == null) {
log.warn("There is no node configuration to update : {}", node.hostname());
return Response.notModified().build();
} else if (!existing.equals(node)) {
adminService.updateNode(node);
nodeAdminService.updateNode(node);
}
}
@ -130,23 +139,22 @@ public class K8sNodeWebResource extends AbstractWebResource {
* @param hostname host name contained in kubernetes nodes configuration
* @return 204 NO_CONTENT, 400 BAD_REQUEST if the JSON is malformed, and
* 304 NOT_MODIFIED without the updated config
* @onos.rsModel K8sNode
*/
@javax.ws.rs.DELETE
@DELETE
@Path("node/{hostname}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Path("{hostname}")
public Response deleteNodes(@PathParam("hostname") String hostname) {
log.trace(String.format(MESSAGE_NODE, DELETE));
log.trace(String.format(MESSAGE_NODE, REMOVE));
K8sNode existing =
adminService.node(nullIsIllegal(hostname, HOST_NAME + ERROR_MESSAGE));
nodeAdminService.node(nullIsIllegal(hostname, HOST_NAME + ERROR_MESSAGE));
if (existing == null) {
log.warn("There is no node configuration to delete : {}", hostname);
return Response.notModified().build();
} else {
adminService.removeNode(hostname);
nodeAdminService.removeNode(hostname);
}
return Response.noContent().build();
@ -175,4 +183,111 @@ public class K8sNodeWebResource extends AbstractWebResource {
return nodeSet;
}
/**
* Creates a set of kubernetes API config from the JSON input stream.
*
* @param input kubernetes API configs JSON input stream
* @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
* is malformed
* @onos.rsModel K8sApiConfig
*/
@POST
@Path("api")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createApiConfigs(InputStream input) {
log.trace(String.format(MESSAGE_NODE, CREATE));
readApiConfigConfiguration(input).forEach(config -> {
K8sApiConfig existing = configAdminService.apiConfig(endpoint(config));
if (existing == null) {
configAdminService.createApiConfig(config);
}
});
UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
.path(API_CONFIGS);
return created(locationBuilder.build()).build();
}
/**
* Updates a set of kubernetes API config from the JSON input stream.
*
* @param input kubernetes API configs JSON input stream
* @return 200 OK with the updated kubernetes API config, 400 BAD_REQUEST
* if the JSON is malformed, and 304 NOT_MODIFIED without the updated config
* @onos.rsModel K8sApiConfig
*/
@PUT
@Path("api")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response updateApiConfigs(InputStream input) {
log.trace(String.format(MESSAGE_NODE, UPDATE));
Set<K8sApiConfig> configs = readApiConfigConfiguration(input);
for (K8sApiConfig config: configs) {
K8sApiConfig existing = configAdminService.apiConfig(endpoint(config));
if (existing == null) {
log.warn("There is no API configuration to update : {}", endpoint(config));
return Response.notModified().build();
} else if (!existing.equals(config)) {
configAdminService.updateApiConfig(config);
}
}
return Response.ok().build();
}
/**
* Removes a kubernetes API config.
*
* @param endpoint kubernetes API endpoint
* @return 204 NO_CONTENT, 400 BAD_REQUEST if the JSON is malformed
*/
@DELETE
@Path("api/{endpoint : .+}")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response deleteApiConfig(@PathParam("endpoint") String endpoint) {
log.trace(String.format(MESSAGE_NODE, REMOVE));
K8sApiConfig existing =
configAdminService.apiConfig(nullIsIllegal(endpoint, ENDPOINT + ERROR_MESSAGE));
if (existing == null) {
log.warn("There is no API configuration to delete : {}", endpoint);
return Response.notModified().build();
} else {
configAdminService.removeApiConfig(endpoint);
}
return Response.noContent().build();
}
private Set<K8sApiConfig> readApiConfigConfiguration(InputStream input) {
Set<K8sApiConfig> configSet = Sets.newHashSet();
try {
JsonNode jsonTree = readTreeFromStream(mapper().enable(INDENT_OUTPUT), input);
ArrayNode configs = (ArrayNode) jsonTree.path(API_CONFIGS);
configs.forEach(config -> {
try {
ObjectNode objectNode = config.deepCopy();
K8sApiConfig k8sApiConfig =
codec(K8sApiConfig.class).decode(objectNode, this);
configSet.add(k8sApiConfig);
} catch (Exception e) {
log.error("Exception occurred due to {}", e);
throw new IllegalArgumentException();
}
});
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
return configSet;
}
}

View File

@ -0,0 +1,33 @@
{
"type": "object",
"required": [
"apiConfigs"
],
"properties": {
"nodes": {
"type": "array",
"items": {
"type": "object",
"required": [
"scheme",
"ipAddress",
"port"
],
"properties": {
"scheme": {
"type": "string",
"example": "HTTP"
},
"ipAddress": {
"type": "string",
"example": "10.10.10.2"
},
"port": {
"type": "integer",
"example": 6443
}
}
}
}
}
}

View File

@ -0,0 +1,156 @@
/*
* Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.k8snode.codec;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.IpAddress;
import org.onosproject.codec.CodecContext;
import org.onosproject.codec.JsonCodec;
import org.onosproject.codec.impl.CodecManager;
import org.onosproject.core.CoreService;
import org.onosproject.k8snode.api.DefaultK8sApiConfig;
import org.onosproject.k8snode.api.K8sApiConfig;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import static junit.framework.TestCase.assertEquals;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.notNullValue;
import static org.onosproject.k8snode.codec.K8sApiConfigJsonMatcher.matchesK8sApiConfig;
import static org.onosproject.net.NetTestTools.APP_ID;
/**
* Unit tests for kubernetes API config codec.
*/
public class K8sApiConfigCodecTest {
MockCodecContext context;
JsonCodec<K8sApiConfig> k8sApiConfigCodec;
final CoreService mockCoreService = createMock(CoreService.class);
private static final String REST_APP_ID = "org.onosproject.rest";
/**
* Initial setup for this unit test.
*/
@Before
public void setUp() {
context = new MockCodecContext();
k8sApiConfigCodec = new K8sApiConfigCodec();
assertThat(k8sApiConfigCodec, notNullValue());
expect(mockCoreService.registerApplication(REST_APP_ID))
.andReturn(APP_ID).anyTimes();
replay(mockCoreService);
context.registerService(CoreService.class, mockCoreService);
}
/**
* Tests the kubernetes API config encoding.
*/
@Test
public void testK8sApiConfigEncode() {
K8sApiConfig config = DefaultK8sApiConfig.builder()
.scheme(K8sApiConfig.Scheme.HTTPS)
.ipAddress(IpAddress.valueOf("10.10.10.23"))
.port(6443)
.token("token")
.caCertData("caCertData")
.clientCertData("clientCertData")
.clientKeyData("clientKeyData")
.build();
ObjectNode configJson = k8sApiConfigCodec.encode(config, context);
assertThat(configJson, matchesK8sApiConfig(config));
}
/**
* Tests the kubernetes API config decoding.
*
* @throws IOException IO exception
*/
@Test
public void testK8sApiConfigDecode() throws IOException {
K8sApiConfig config = getK8sApiConfig("K8sApiConfig.json");
assertEquals("HTTPS", config.scheme().name());
assertEquals("10.134.34.223", config.ipAddress().toString());
assertEquals(6443, config.port());
assertEquals("token", config.token());
assertEquals("caCertData", config.caCertData());
assertEquals("clientCertData", config.clientCertData());
assertEquals("clientKeyData", config.clientKeyData());
}
private K8sApiConfig getK8sApiConfig(String resourceName) throws IOException {
InputStream jsonStream = K8sNodeCodecTest.class.getResourceAsStream(resourceName);
JsonNode json = context.mapper().readTree(jsonStream);
assertThat(json, notNullValue());
K8sApiConfig config = k8sApiConfigCodec.decode((ObjectNode) json, context);
assertThat(config, notNullValue());
return config;
}
private class MockCodecContext implements CodecContext {
private final ObjectMapper mapper = new ObjectMapper();
private final CodecManager manager = new CodecManager();
private final Map<Class<?>, Object> services = new HashMap<>();
/**
* Constructs a new mock codec context.
*/
public MockCodecContext() {
manager.activate();
}
@Override
public ObjectMapper mapper() {
return mapper;
}
@Override
@SuppressWarnings("unchecked")
public <T> JsonCodec<T> codec(Class<T> entityClass) {
if (entityClass == K8sApiConfig.class) {
return (JsonCodec<T>) k8sApiConfigCodec;
}
return manager.getCodec(entityClass);
}
@SuppressWarnings("unchecked")
@Override
public <T> T getService(Class<T> serviceClass) {
return (T) services.get(serviceClass);
}
// for registering mock services
public <T> void registerService(Class<T> serviceClass, T impl) {
services.put(serviceClass, impl);
}
}
}

View File

@ -0,0 +1,128 @@
/*
* Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.k8snode.codec;
import com.fasterxml.jackson.databind.JsonNode;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeDiagnosingMatcher;
import org.onosproject.k8snode.api.K8sApiConfig;
/**
* Hamcrest matcher for kubernetes API config.
*/
public final class K8sApiConfigJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
private final K8sApiConfig k8sApiConfig;
private static final String SCHEME = "scheme";
private static final String IP_ADDRESS = "ipAddress";
private static final String PORT = "port";
private static final String TOKEN = "token";
private static final String CA_CERT_DATA = "caCertData";
private static final String CLIENT_CERT_DATA = "clientCertData";
private static final String CLIENT_KEY_DATA = "clientKeyData";
private K8sApiConfigJsonMatcher(K8sApiConfig k8sApiConfig) {
this.k8sApiConfig = k8sApiConfig;
}
@Override
protected boolean matchesSafely(JsonNode jsonNode, Description description) {
// check scheme
String jsonScheme = jsonNode.get(SCHEME).asText();
String scheme = k8sApiConfig.scheme().name();
if (!jsonScheme.equals(scheme)) {
description.appendText("scheme was " + jsonScheme);
return false;
}
// check IP address
String jsonIpAddress = jsonNode.get(IP_ADDRESS).asText();
String ipAddress = k8sApiConfig.ipAddress().toString();
if (!jsonIpAddress.equals(ipAddress)) {
description.appendText("ipAddress was " + jsonIpAddress);
return false;
}
// check port
int jsonPort = jsonNode.get(PORT).asInt();
int port = k8sApiConfig.port();
if (jsonPort != port) {
description.appendText("port was " + jsonPort);
return false;
}
// check token
JsonNode jsonToken = jsonNode.get(TOKEN);
String token = k8sApiConfig.token();
if (jsonToken != null) {
if (!jsonToken.asText().equals(token)) {
description.appendText("token was " + jsonToken);
return false;
}
}
// check caCertData
JsonNode jsonCaCertData = jsonNode.get(CA_CERT_DATA);
String caCertData = k8sApiConfig.caCertData();
if (jsonCaCertData != null) {
if (!jsonCaCertData.asText().equals(caCertData)) {
description.appendText("caCertData was " + jsonCaCertData);
return false;
}
}
// check clientCertData
JsonNode jsonClientCertData = jsonNode.get(CLIENT_CERT_DATA);
String clientCertData = k8sApiConfig.clientCertData();
if (jsonClientCertData != null) {
if (!jsonClientCertData.asText().equals(clientCertData)) {
description.appendText("clientCertData was " + jsonClientCertData);
return false;
}
}
// check clientKeyData
JsonNode jsonClientKeyData = jsonNode.get(CLIENT_KEY_DATA);
String clientKeyData = k8sApiConfig.clientKeyData();
if (jsonClientKeyData != null) {
if (!jsonClientKeyData.asText().equals(clientKeyData)) {
description.appendText("clientKeyData was " + jsonClientKeyData);
return false;
}
}
return true;
}
@Override
public void describeTo(Description description) {
description.appendText(k8sApiConfig.toString());
}
/**
* Factory to allocate an k8sApiConfig matcher.
*
* @param config k8sApiConfig object we are looking for
* @return matcher
*/
public static K8sApiConfigJsonMatcher matchesK8sApiConfig(K8sApiConfig config) {
return new K8sApiConfigJsonMatcher(config);
}
}

View File

@ -0,0 +1,225 @@
/*
* Copyright 2019-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.k8snode.impl;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.MoreExecutors;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.junit.TestUtils;
import org.onlab.packet.IpAddress;
import org.onosproject.cluster.ClusterServiceAdapter;
import org.onosproject.cluster.LeadershipServiceAdapter;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreServiceAdapter;
import org.onosproject.core.DefaultApplicationId;
import org.onosproject.event.Event;
import org.onosproject.k8snode.api.DefaultK8sApiConfig;
import org.onosproject.k8snode.api.K8sApiConfig;
import org.onosproject.k8snode.api.K8sApiConfigEvent;
import org.onosproject.k8snode.api.K8sApiConfigListener;
import org.onosproject.store.service.TestStorageService;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.onosproject.k8snode.api.K8sApiConfigEvent.Type.K8S_API_CONFIG_CREATED;
import static org.onosproject.k8snode.api.K8sApiConfigEvent.Type.K8S_API_CONFIG_REMOVED;
import static org.onosproject.k8snode.util.K8sNodeUtil.endpoint;
/**
* Unit tests for kubernetes API config manager.
*/
public class K8sApiConfigManagerTest {
private static final ApplicationId TEST_APP_ID = new DefaultApplicationId(1, "test");
private static final String ERR_SIZE = "Number of configs did not match";
private static final String ERR_NOT_MATCH = "Config did not match";
private static final String ERR_NOT_FOUND = "Config did not exist";
private K8sApiConfig apiConfig1;
private K8sApiConfig apiConfig2;
private K8sApiConfig apiConfig3;
private final TestK8sApiConfigListener testListener = new TestK8sApiConfigListener();
private K8sApiConfigManager target;
private DistributedK8sApiConfigStore configStore;
/**
* Initial setup for this unit test.
*/
@Before
public void setUp() {
apiConfig1 = DefaultK8sApiConfig.builder()
.scheme(K8sApiConfig.Scheme.HTTP)
.ipAddress(IpAddress.valueOf("10.10.10.2"))
.port(6443)
.build();
apiConfig2 = DefaultK8sApiConfig.builder()
.scheme(K8sApiConfig.Scheme.HTTPS)
.ipAddress(IpAddress.valueOf("10.10.10.3"))
.port(6443)
.token("token")
.caCertData("caCertData")
.clientCertData("clientCertData")
.clientKeyData("clientKeyData")
.build();
apiConfig3 = DefaultK8sApiConfig.builder()
.scheme(K8sApiConfig.Scheme.HTTP)
.ipAddress(IpAddress.valueOf("10.10.10.4"))
.port(8080)
.build();
configStore = new DistributedK8sApiConfigStore();
TestUtils.setField(configStore, "coreService", new TestCoreService());
TestUtils.setField(configStore, "storageService", new TestStorageService());
TestUtils.setField(configStore, "eventExecutor", MoreExecutors.newDirectExecutorService());
configStore.activate();
configStore.createApiConfig(apiConfig2);
configStore.createApiConfig(apiConfig3);
target = new K8sApiConfigManager();
target.storageService = new TestStorageService();
target.coreService = new TestCoreService();
target.clusterService = new TestClusterService();
target.leadershipService = new TestLeadershipService();
target.configStore = configStore;
target.addListener(testListener);
target.activate();
testListener.events.clear();
}
/**
* Clean up unit test.
*/
@After
public void tearDown() {
target.removeListener(testListener);
target.deactivate();
configStore.deactivate();
configStore = null;
target = null;
}
/**
* Checks if creating and removing a config work well with proper events.
*/
@Test
public void testCreateAndRemoveConfig() {
target.createApiConfig(apiConfig1);
assertEquals(ERR_SIZE, 3, target.apiConfigs().size());
assertNotNull(target.apiConfig(endpoint(apiConfig1)));
target.removeApiConfig(endpoint(apiConfig1));
assertEquals(ERR_SIZE, 2, target.apiConfigs().size());
assertNull(target.apiConfig(endpoint(apiConfig1)));
validateEvents(K8S_API_CONFIG_CREATED, K8S_API_CONFIG_REMOVED);
}
/**
* Checks if creating null config fails with proper exception.
*/
@Test(expected = NullPointerException.class)
public void testCreateNullConfig() {
target.createApiConfig(null);
}
private static class TestK8sApiConfigListener implements K8sApiConfigListener {
private List<K8sApiConfigEvent> events = Lists.newArrayList();
@Override
public void event(K8sApiConfigEvent event) {
events.add(event);
}
}
/**
* Checks if creating a duplicated config fails with proper exception.
*/
@Test(expected = IllegalArgumentException.class)
public void testCreateDuplicateConfig() {
target.createApiConfig(apiConfig1);
target.createApiConfig(apiConfig1);
}
/**
* Checks if removing null config fails with proper exception.
*/
@Test(expected = IllegalArgumentException.class)
public void testRemoveNullConfig() {
target.removeApiConfig(null);
}
private void validateEvents(Enum... types) {
int i = 0;
assertEquals("Number of events did not match", types.length, testListener.events.size());
for (Event event : testListener.events) {
assertEquals("Incorrect event received", types[i], event.type());
i++;
}
testListener.events.clear();
}
/**
* Checks if updating a null config fails with proper exception.
*/
@Test(expected = NullPointerException.class)
public void testUpdateNullConfig() {
target.updateApiConfig(null);
}
/**
* Checks if updating not existing config fails with proper exception.
*/
@Test(expected = IllegalArgumentException.class)
public void testUpdateNotExistingConfig() {
target.updateApiConfig(apiConfig1);
}
/**
* Checks if getting all nodes method returns correct set of nodes.
*/
@Test
public void testGetAllNodes() {
assertEquals(ERR_SIZE, 2, target.apiConfigs().size());
assertTrue(ERR_NOT_FOUND, target.apiConfigs().contains(apiConfig2));
assertTrue(ERR_NOT_FOUND, target.apiConfigs().contains(apiConfig3));
}
private static class TestCoreService extends CoreServiceAdapter {
@Override
public ApplicationId registerApplication(String name) {
return TEST_APP_ID;
}
}
private class TestClusterService extends ClusterServiceAdapter {
}
private static class TestLeadershipService extends LeadershipServiceAdapter {
}
}

View File

@ -23,10 +23,14 @@ import org.onlab.osgi.TestServiceDirectory;
import org.onlab.packet.IpAddress;
import org.onosproject.codec.CodecService;
import org.onosproject.codec.impl.CodecManager;
import org.onosproject.k8snode.api.DefaultK8sApiConfig;
import org.onosproject.k8snode.api.DefaultK8sNode;
import org.onosproject.k8snode.api.K8sApiConfig;
import org.onosproject.k8snode.api.K8sApiConfigAdminService;
import org.onosproject.k8snode.api.K8sNode;
import org.onosproject.k8snode.api.K8sNodeAdminService;
import org.onosproject.k8snode.api.K8sNodeState;
import org.onosproject.k8snode.codec.K8sApiConfigCodec;
import org.onosproject.k8snode.codec.K8sNodeCodec;
import org.onosproject.net.DeviceId;
import org.onosproject.rest.resources.ResourceTest;
@ -52,9 +56,13 @@ import static org.junit.Assert.assertThat;
public class K8sNodeWebResourceTest extends ResourceTest {
final K8sNodeAdminService mockK8sNodeAdminService = createMock(K8sNodeAdminService.class);
private static final String PATH = "configure";
final K8sApiConfigAdminService mockK8sApiConfigAdminService =
createMock(K8sApiConfigAdminService.class);
private static final String NODE_PATH = "configure/node";
private static final String API_PATH = "configure/api";
private K8sNode k8sNode;
private K8sApiConfig k8sApiConfig;
/**
* Constructs a kubernetes node resource test instance.
@ -71,9 +79,11 @@ public class K8sNodeWebResourceTest extends ResourceTest {
final CodecManager codecService = new CodecManager();
codecService.activate();
codecService.registerCodec(K8sNode.class, new K8sNodeCodec());
codecService.registerCodec(K8sApiConfig.class, new K8sApiConfigCodec());
ServiceDirectory testDirectory =
new TestServiceDirectory()
.add(K8sNodeAdminService.class, mockK8sNodeAdminService)
.add(K8sApiConfigAdminService.class, mockK8sApiConfigAdminService)
.add(CodecService.class, codecService);
setServiceDirectory(testDirectory);
@ -85,6 +95,16 @@ public class K8sNodeWebResourceTest extends ResourceTest {
.intgBridge(DeviceId.deviceId("of:00000000000000a1"))
.state(K8sNodeState.INIT)
.build();
k8sApiConfig = DefaultK8sApiConfig.builder()
.scheme(K8sApiConfig.Scheme.HTTPS)
.ipAddress(IpAddress.valueOf("10.134.34.223"))
.port(6443)
.token("tokenMod")
.caCertData("caCertData")
.clientCertData("clientCertData")
.clientKeyData("clientKeyData")
.build();
}
/**
@ -99,7 +119,7 @@ public class K8sNodeWebResourceTest extends ResourceTest {
final WebTarget wt = target();
InputStream jsonStream = K8sNodeWebResourceTest.class
.getResourceAsStream("k8s-node-minion-config.json");
Response response = wt.path(PATH).request(MediaType.APPLICATION_JSON_TYPE)
Response response = wt.path(NODE_PATH).request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.json(jsonStream));
final int status = response.getStatus();
@ -119,7 +139,7 @@ public class K8sNodeWebResourceTest extends ResourceTest {
final WebTarget wt = target();
InputStream jsonStream = K8sNodeWebResourceTest.class
.getResourceAsStream("k8s-node-minion-config.json");
Response response = wt.path(PATH).request(MediaType.APPLICATION_JSON_TYPE)
Response response = wt.path(NODE_PATH).request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.json(jsonStream));
final int status = response.getStatus();
@ -140,7 +160,7 @@ public class K8sNodeWebResourceTest extends ResourceTest {
final WebTarget wt = target();
InputStream jsonStream = K8sNodeWebResourceTest.class
.getResourceAsStream("k8s-node-minion-config.json");
Response response = wt.path(PATH).request(MediaType.APPLICATION_JSON_TYPE)
Response response = wt.path(NODE_PATH).request(MediaType.APPLICATION_JSON_TYPE)
.put(Entity.json(jsonStream));
final int status = response.getStatus();
@ -160,7 +180,7 @@ public class K8sNodeWebResourceTest extends ResourceTest {
final WebTarget wt = target();
InputStream jsonStream = K8sNodeWebResourceTest.class
.getResourceAsStream("k8s-node-minion-config.json");
Response response = wt.path(PATH).request(MediaType.APPLICATION_JSON_TYPE)
Response response = wt.path(NODE_PATH).request(MediaType.APPLICATION_JSON_TYPE)
.put(Entity.json(jsonStream));
final int status = response.getStatus();
@ -178,7 +198,7 @@ public class K8sNodeWebResourceTest extends ResourceTest {
expect(mockK8sNodeAdminService.removeNode(anyString())).andReturn(k8sNode).once();
replay(mockK8sNodeAdminService);
String location = PATH + "/minion-node";
String location = NODE_PATH + "/minion-node";
final WebTarget wt = target();
Response response = wt.path(location).request(
@ -199,7 +219,7 @@ public class K8sNodeWebResourceTest extends ResourceTest {
expect(mockK8sNodeAdminService.node(anyString())).andReturn(null).once();
replay(mockK8sNodeAdminService);
String location = PATH + "/minion-node";
String location = NODE_PATH + "/minion-node";
final WebTarget wt = target();
Response response = wt.path(location).request(
@ -211,4 +231,132 @@ public class K8sNodeWebResourceTest extends ResourceTest {
verify(mockK8sNodeAdminService);
}
/**
* Tests the results of the REST API POST method with creating new configs operation.
*/
@Test
public void testCreateConfigsWithCreateOperation() {
expect(mockK8sApiConfigAdminService.apiConfig(anyString())).andReturn(null).once();
mockK8sApiConfigAdminService.createApiConfig(anyObject());
replay(mockK8sApiConfigAdminService);
final WebTarget wt = target();
InputStream jsonStream = K8sNodeWebResourceTest.class
.getResourceAsStream("k8s-api-config.json");
Response response = wt.path(API_PATH).request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.json(jsonStream));
final int status = response.getStatus();
assertThat(status, is(201));
verify(mockK8sApiConfigAdminService);
}
/**
* Tests the results of the REST API POST method without creating new configs operation.
*/
@Test
public void testCreateConfigsWithoutCreateOperation() {
expect(mockK8sApiConfigAdminService.apiConfig(anyString())).andReturn(k8sApiConfig).once();
replay(mockK8sApiConfigAdminService);
final WebTarget wt = target();
InputStream jsonStream = K8sNodeWebResourceTest.class
.getResourceAsStream("k8s-api-config.json");
Response response = wt.path(API_PATH).request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.json(jsonStream));
final int status = response.getStatus();
assertThat(status, is(201));
verify(mockK8sApiConfigAdminService);
}
/**
* Tests the results of the REST API PUT method with modifying the configs.
*/
@Test
public void testUpdateConfigsWithModifyOperation() {
expect(mockK8sApiConfigAdminService.apiConfig(anyString()))
.andReturn(k8sApiConfig).once();
mockK8sApiConfigAdminService.updateApiConfig(anyObject());
replay(mockK8sApiConfigAdminService);
final WebTarget wt = target();
InputStream jsonStream = K8sNodeWebResourceTest.class
.getResourceAsStream("k8s-api-config.json");
Response response = wt.path(API_PATH).request(MediaType.APPLICATION_JSON_TYPE)
.put(Entity.json(jsonStream));
final int status = response.getStatus();
assertThat(status, is(200));
verify(mockK8sApiConfigAdminService);
}
/**
* Tests the results of the REST API PUT method without modifying the configs.
*/
@Test
public void testUpdateConfigsWithoutModifyOperation() {
expect(mockK8sApiConfigAdminService.apiConfig(anyString())).andReturn(null).once();
replay(mockK8sApiConfigAdminService);
final WebTarget wt = target();
InputStream jsonStream = K8sNodeWebResourceTest.class
.getResourceAsStream("k8s-api-config.json");
Response response = wt.path(API_PATH).request(MediaType.APPLICATION_JSON_TYPE)
.put(Entity.json(jsonStream));
final int status = response.getStatus();
assertThat(status, is(304));
verify(mockK8sApiConfigAdminService);
}
/**
* Tests the results of the REST API DELETE method with deleting the configs.
*/
@Test
public void testDeleteConfigsWithDeletionOperation() {
expect(mockK8sApiConfigAdminService.apiConfig(anyString()))
.andReturn(k8sApiConfig).once();
expect(mockK8sApiConfigAdminService.removeApiConfig(anyString()))
.andReturn(k8sApiConfig).once();
replay(mockK8sApiConfigAdminService);
String location = API_PATH + "/https://test:8663";
final WebTarget wt = target();
Response response = wt.path(location).request(
MediaType.APPLICATION_JSON_TYPE).delete();
final int status = response.getStatus();
assertThat(status, is(204));
verify(mockK8sApiConfigAdminService);
}
/**
* Tests the results of the REST API DELETE method without deleting the configs.
*/
@Test
public void testDeleteConfigsWithoutDeletionOperation() {
expect(mockK8sApiConfigAdminService.apiConfig(anyString())).andReturn(null).once();
replay(mockK8sApiConfigAdminService);
String location = API_PATH + "/https://test:8663";
final WebTarget wt = target();
Response response = wt.path(location).request(
MediaType.APPLICATION_JSON_TYPE).delete();
final int status = response.getStatus();
assertThat(status, is(304));
verify(mockK8sApiConfigAdminService);
}
}

View File

@ -0,0 +1,9 @@
{
"scheme" : "HTTPS",
"ipAddress" : "10.134.34.223",
"port" : 6443,
"token": "token",
"caCertData": "caCertData",
"clientCertData": "clientCertData",
"clientKeyData": "clientKeyData"
}

View File

@ -0,0 +1,13 @@
{
"apiConfigs" : [
{
"scheme" : "HTTPS",
"ipAddress" : "10.134.34.223",
"port" : 6443,
"token": "token",
"caCertData": "caCertData",
"clientCertData": "clientCertData",
"clientKeyData": "clientKeyData"
}
]
}

View File

@ -304,6 +304,13 @@
"msg-simple": "mvn:com.github.fge:msg-simple:1.1",
"snakeyaml": "mvn:org.yaml:snakeyaml:1.15",
// Kubernetes related jars
"k8s-client": "mvn:io.fabric8:kubernetes-client:4.1.1",
"k8s-model": "mvn:io.fabric8:kubernetes-model:4.1.1",
"zjsonpatch": "mvn:io.fabric8:zjsonpatch:0.3.0",
"generex": "mvn:com.github.mifmif:generex:1.0.2",
"automaton": "mvn:dk.brics.automaton:automaton:1.11-8",
"onos-yang-model":"mvn:org.onosproject:onos-yang-model:2.6.1",
"onos-yang-compiler-api":"mvn:org.onosproject:onos-yang-compiler-api:2.6.1",
"onos-yang-compiler-main":"mvn:org.onosproject:onos-yang-compiler-main:2.6.1",

View File

@ -1156,6 +1156,36 @@ def generated_maven_jars():
jar_sha256 = "79ea8aac6590f49ee8390c2f17ed9343079e85b44158a097b301dfee42af86ec",
licenses = ["notice"],
jar_urls = ["http://repo1.maven.org/maven2/org/yaml/snakeyaml/1.15/snakeyaml-1.15.jar"], )
if "k8s_client" not in native.existing_rules():
java_import_external(
name = "k8s_client",
jar_sha256 = "b3dd82d2fb2d566a4ba49c64456649a78fa1035135b3ac9b73b4f9d6ee5b2a86",
licenses = ["notice"],
jar_urls = ["http://repo1.maven.org/maven2/io/fabric8/kubernetes-client/4.1.1/kubernetes-client-4.1.1.jar"], )
if "k8s_model" not in native.existing_rules():
java_import_external(
name = "k8s_model",
jar_sha256 = "ef53a674d73d518b5897cbd38032aa4e9e2b083ef236fd32cc0e4bedd837c38b",
licenses = ["notice"],
jar_urls = ["http://repo1.maven.org/maven2/io/fabric8/kubernetes-model/4.1.1/kubernetes-model-4.1.1.jar"], )
if "zjsonpatch" not in native.existing_rules():
java_import_external(
name = "zjsonpatch",
jar_sha256 = "ae4e5e931646a25cb09b55186de4f3346e358e01130bef279ddf495a719c71d5",
licenses = ["notice"],
jar_urls = ["http://repo1.maven.org/maven2/io/fabric8/zjsonpatch/0.3.0/zjsonpatch-0.3.0.jar"], )
if "generex" not in native.existing_rules():
java_import_external(
name = "generex",
jar_sha256 = "8f8ce233c335e08e113a3f9579de1046fb19927e82468b1bbebcd6cba8760b81",
licenses = ["notice"],
jar_urls = ["http://repo1.maven.org/maven2/com/github/mifmif/generex/1.0.2/generex-1.0.2.jar"], )
if "automaton" not in native.existing_rules():
java_import_external(
name = "automaton",
jar_sha256 = "a24475f6ccfe1cc7a4fe9e34e05ce687b0ce0c6e8cb781e0eced3b186482c61e",
licenses = ["notice"],
jar_urls = ["http://repo1.maven.org/maven2/dk/brics/automaton/automaton/1.11-8/automaton-1.11-8.jar"], )
if "onos_yang_model" not in native.existing_rules():
java_import_external(
name = "onos_yang_model",
@ -1455,6 +1485,11 @@ artifact_map["@jackson_coreutils//:jackson_coreutils"] = "mvn:com.github.fge:jac
artifact_map["@btf//:btf"] = "mvn:com.github.fge:btf:jar:1.2"
artifact_map["@msg_simple//:msg_simple"] = "mvn:com.github.fge:msg-simple:jar:1.1"
artifact_map["@snakeyaml//:snakeyaml"] = "mvn:org.yaml:snakeyaml:jar:1.15"
artifact_map["@k8s_client//:k8s_client"] = "mvn:io.fabric8:kubernetes-client:jar:NON-OSGI:4.1.1"
artifact_map["@k8s_model//:k8s_model"] = "mvn:io.fabric8:kubernetes-model:jar:4.1.1"
artifact_map["@zjsonpatch//:zjsonpatch"] = "mvn:io.fabric8:zjsonpatch:jar:0.3.0"
artifact_map["@generex//:generex"] = "mvn:com.github.mifmif:generex:jar:NON-OSGI:1.0.2"
artifact_map["@automaton//:automaton"] = "mvn:dk.brics.automaton:automaton:jar:NON-OSGI:1.11-8"
artifact_map["@onos_yang_model//:onos_yang_model"] = "mvn:org.onosproject:onos-yang-model:jar:2.6.1"
artifact_map["@onos_yang_compiler_api//:onos_yang_compiler_api"] = "mvn:org.onosproject:onos-yang-compiler-api:jar:2.6.1"
artifact_map["@onos_yang_compiler_main//:onos_yang_compiler_main"] = "mvn:org.onosproject:onos-yang-compiler-main:jar:2.6.1"