mirror of
https://github.com/opennetworkinglab/onos.git
synced 2026-05-04 19:56:49 +02:00
Import k8s client deps, support inject k8s API server config
Change-Id: Iaf246a06462b8a878e93ef3f98da399c3600b129
This commit is contained in:
parent
ec0f7483c3
commit
3defa842eb
@ -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(
|
||||
|
||||
@ -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 + [
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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() {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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> {
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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> {
|
||||
}
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
{
|
||||
"scheme" : "HTTPS",
|
||||
"ipAddress" : "10.134.34.223",
|
||||
"port" : 6443,
|
||||
"token": "token",
|
||||
"caCertData": "caCertData",
|
||||
"clientCertData": "clientCertData",
|
||||
"clientKeyData": "clientKeyData"
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
{
|
||||
"apiConfigs" : [
|
||||
{
|
||||
"scheme" : "HTTPS",
|
||||
"ipAddress" : "10.134.34.223",
|
||||
"port" : 6443,
|
||||
"token": "token",
|
||||
"caCertData": "caCertData",
|
||||
"clientCertData": "clientCertData",
|
||||
"clientKeyData": "clientKeyData"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -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",
|
||||
|
||||
@ -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"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user