diff --git a/api/cmd/portainer/main.go b/api/cmd/portainer/main.go index f0a13ebdc..8a8d0e08f 100644 --- a/api/cmd/portainer/main.go +++ b/api/cmd/portainer/main.go @@ -6,6 +6,8 @@ import ( "strings" "time" + "github.com/jpillora/chisel/server" + "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/bolt" "github.com/portainer/portainer/api/cli" @@ -641,6 +643,12 @@ func main() { go terminateIfNoAdminCreated(store.UserService) } + chiselServer, err := chserver.NewServer(&chserver.Config{Reverse: true}) + if err != nil { + log.Fatal(err) + } + chiselServer.Start("0.0.0.0", "9999") + var server portainer.Server = &http.Server{ Status: applicationStatus, BindAddress: *flags.Addr, diff --git a/api/http/handler/endpointproxy/proxy_docker.go b/api/http/handler/endpointproxy/proxy_docker.go index 7a0834c82..ae2a24b14 100644 --- a/api/http/handler/endpointproxy/proxy_docker.go +++ b/api/http/handler/endpointproxy/proxy_docker.go @@ -24,7 +24,7 @@ func (handler *Handler) proxyRequestsToDockerAPI(w http.ResponseWriter, r *http. return &httperror.HandlerError{http.StatusInternalServerError, "Unable to find an endpoint with the specified identifier inside the database", err} } - if endpoint.Status == portainer.EndpointStatusDown { + if endpoint.Type != 4 && endpoint.Status == portainer.EndpointStatusDown { return &httperror.HandlerError{http.StatusServiceUnavailable, "Unable to query endpoint", errors.New("Endpoint is down")} } diff --git a/api/http/handler/endpoints/endpoint_create.go b/api/http/handler/endpoints/endpoint_create.go index 34e06cca4..0610afa5f 100644 --- a/api/http/handler/endpoints/endpoint_create.go +++ b/api/http/handler/endpoints/endpoint_create.go @@ -1,6 +1,8 @@ package endpoints import ( + "encoding/base64" + "strings" "log" "net/http" "runtime" @@ -41,7 +43,7 @@ func (payload *endpointCreatePayload) Validate(r *http.Request) error { endpointType, err := request.RetrieveNumericMultiPartFormValue(r, "EndpointType", false) if err != nil || endpointType == 0 { - return portainer.Error("Invalid endpoint type value. Value must be one of: 1 (Docker environment), 2 (Agent environment) or 3 (Azure environment)") + return portainer.Error("Invalid endpoint type value. Value must be one of: 1 (Docker environment), 2 (Agent environment), 3 (Azure environment) or 4 (Agent IoT environment)") } payload.EndpointType = endpointType @@ -149,6 +151,8 @@ func (handler *Handler) endpointCreate(w http.ResponseWriter, r *http.Request) * func (handler *Handler) createEndpoint(payload *endpointCreatePayload) (*portainer.Endpoint, *httperror.HandlerError) { if portainer.EndpointType(payload.EndpointType) == portainer.AzureEnvironment { return handler.createAzureEndpoint(payload) + } else if portainer.EndpointType(payload.EndpointType) == portainer.AgentIoTEnvironment { + return handler.createAgentIoTEndpoint(payload) } if payload.TLS { @@ -195,6 +199,38 @@ func (handler *Handler) createAzureEndpoint(payload *endpointCreatePayload) (*po return endpoint, nil } +func (handler *Handler) createAgentIoTEndpoint(payload *endpointCreatePayload) (*portainer.Endpoint, *httperror.HandlerError) { + endpointType := portainer.AgentIoTEnvironment + endpointID := handler.EndpointService.GetNextIdentifier() + + iotKey := base64.RawStdEncoding.EncodeToString([]byte(strings.TrimPrefix(payload.URL, "tcp://") + ":9999:7777:random_secret")) + + endpoint := &portainer.Endpoint{ + ID: portainer.EndpointID(endpointID), + Name: payload.Name, + URL: "tcp://localhost:7777", + Type: endpointType, + GroupID: portainer.EndpointGroupID(payload.GroupID), + TLSConfig: portainer.TLSConfiguration{ + TLS: false, + }, + AuthorizedUsers: []portainer.UserID{}, + AuthorizedTeams: []portainer.TeamID{}, + Extensions: []portainer.EndpointExtension{}, + Tags: payload.Tags, + Status: portainer.EndpointStatusUp, + Snapshots: []portainer.Snapshot{}, + IoTKey: iotKey, + } + + err := handler.EndpointService.CreateEndpoint(endpoint) + if err != nil { + return nil, &httperror.HandlerError{http.StatusInternalServerError, "Unable to persist endpoint inside the database", err} + } + + return endpoint, nil +} + func (handler *Handler) createUnsecuredEndpoint(payload *endpointCreatePayload) (*portainer.Endpoint, *httperror.HandlerError) { endpointType := portainer.DockerEnvironment diff --git a/api/portainer.go b/api/portainer.go index 0b2eff4f4..9ed73321e 100644 --- a/api/portainer.go +++ b/api/portainer.go @@ -242,6 +242,7 @@ type ( Tags []string `json:"Tags"` Status EndpointStatus `json:"Status"` Snapshots []Snapshot `json:"Snapshots"` + IoTKey string `json:"IoTKey"` // Deprecated fields // Deprecated in DBVersion == 4 @@ -893,6 +894,8 @@ const ( AgentOnDockerEnvironment // AzureEnvironment represents an endpoint connected to an Azure environment AzureEnvironment + // AgentIoTEnvironment represents an endpoint connected to an agent using a tunnel + AgentIoTEnvironment ) const ( diff --git a/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.html b/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.html index d83793598..a10d1d27a 100644 --- a/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.html +++ b/app/portainer/components/datatables/endpoints-datatable/endpointsDatatable.html @@ -74,7 +74,8 @@ {{ item.Type | endpointtypename }} -
Portainer agent
+