-
Notifications
You must be signed in to change notification settings - Fork 535
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Opsgenie plugin implementation (#6154)
* feat: Opsgenie plugin implementation * fix(lint): lint with gofmt * refactor(lint): removing unused config-ui files * feat(task): changed incident collector to accept incremental collection * fix(config-ui): adjust the params for bp add connection (#6241) * refactor: removed unused code (#6243) * refactor(config-ui): remove content about user info (#6245) * fix(azure): fix 400 error when cloing azure repos (#6246) * fix: normalize_bp_settings throws error (#6249) * fix: normalize_bp_settings throws error * fix: pg ci * fix: pg ci (#6252) * fix(gitlab): fix incremental deployment collector (#6254) * fix(gitlab): fix incremental deployment collector * fix(gitlab): rollback to full collector * refactor(gitlab): remove unused codes * fix(gitlab): collect deployment incrementally * fix: modify _tool_jira_issue_relationships primary key (#6253) * fix: modify _tool_jira_issue_relationships primary key * fix: ci lint * feat(pagerduty): search remote scope by keyword (#6255) * feat(pagerduty): search remote scope by keyword * feat(pagerduty): add `createdAt` field * refactor(impl): refactoring impl.go and service model * refactor(comment): removing comment from incident collector * feat(task): added GetCreated function * feat(zentao): check db url when testing connections (#6258) * feat(zentao): check db url when testing connections * fix(zentao): remove test codes * fix(zentao): remove test codes * fix(configui): tagsLimit should be a number (#6261) * fix(check): fixing lint in config-ui * refactor(newline): adding removed newline * fix(config-ui): removed old plugin type * refactor(config-ui): remove type inheritance from opsgenieconfig * style(config-ui): update icon with icon.svg --------- Co-authored-by: 青湛 <[email protected]> Co-authored-by: Klesh Wong <[email protected]> Co-authored-by: Lynwee <[email protected]> Co-authored-by: abeizn <[email protected]>
- Loading branch information
1 parent
3efad6a
commit 4453aa5
Showing
70 changed files
with
5,030 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
/* | ||
Licensed to the Apache Software Foundation (ASF) under one or more | ||
contributor license agreements. See the NOTICE file distributed with | ||
this work for additional information regarding copyright ownership. | ||
The ASF licenses this file to You 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 api | ||
|
||
import ( | ||
"github.com/apache/incubator-devlake/core/errors" | ||
coreModels "github.com/apache/incubator-devlake/core/models" | ||
"github.com/apache/incubator-devlake/core/models/domainlayer" | ||
"github.com/apache/incubator-devlake/core/models/domainlayer/didgen" | ||
"github.com/apache/incubator-devlake/core/models/domainlayer/ticket" | ||
"github.com/apache/incubator-devlake/core/plugin" | ||
"github.com/apache/incubator-devlake/core/utils" | ||
"github.com/apache/incubator-devlake/helpers/pluginhelper/api" | ||
"github.com/apache/incubator-devlake/plugins/opsgenie/models" | ||
"github.com/apache/incubator-devlake/plugins/opsgenie/tasks" | ||
) | ||
|
||
func MakeDataSourcePipelinePlanV200( | ||
subtaskMetas []plugin.SubTaskMeta, | ||
connectionId uint64, | ||
bpScopes []*coreModels.BlueprintScope, | ||
) (coreModels.PipelinePlan, []plugin.Scope, errors.Error) { | ||
// get the connection info for url | ||
connection := &models.OpsgenieConnection{} | ||
err := connectionHelper.FirstById(connection, connectionId) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
plan := make(coreModels.PipelinePlan, len(bpScopes)) | ||
plan, err = makeDataSourcePipelinePlanV200(subtaskMetas, plan, bpScopes, connection) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
scopes, err := makeScopesV200(bpScopes, connection) | ||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
return plan, scopes, nil | ||
} | ||
|
||
func makeDataSourcePipelinePlanV200( | ||
subtaskMetas []plugin.SubTaskMeta, | ||
plan coreModels.PipelinePlan, | ||
bpScopes []*coreModels.BlueprintScope, | ||
connection *models.OpsgenieConnection, | ||
) (coreModels.PipelinePlan, errors.Error) { | ||
for i, bpScope := range bpScopes { | ||
// get board and scope config from db | ||
service, scopeConfig, err := scopeHelper.DbHelper().GetScopeAndConfig(connection.ID, bpScope.ScopeId) | ||
if err != nil { | ||
return nil, err | ||
} | ||
// construct task options for opsgenie | ||
op := &tasks.OpsgenieOptions{ | ||
ConnectionId: service.ConnectionId, | ||
ServiceId: service.Id, | ||
ServiceName: service.Name, | ||
} | ||
|
||
var options map[string]any | ||
options, err = tasks.EncodeTaskOptions(op) | ||
if err != nil { | ||
return nil, err | ||
} | ||
var subtasks []string | ||
subtasks, err = api.MakePipelinePlanSubtasks(subtaskMetas, scopeConfig.Entities) | ||
if err != nil { | ||
return nil, err | ||
} | ||
stage := []*coreModels.PipelineTask{ | ||
{ | ||
Plugin: "opsgenie", | ||
Subtasks: subtasks, | ||
Options: options, | ||
}, | ||
} | ||
plan[i] = stage | ||
} | ||
return plan, nil | ||
} | ||
|
||
func makeScopesV200(bpScopes []*coreModels.BlueprintScope, connection *models.OpsgenieConnection) ([]plugin.Scope, errors.Error) { | ||
scopes := make([]plugin.Scope, 0) | ||
for _, bpScope := range bpScopes { | ||
// get board and scope config from db | ||
service, scopeConfig, err := scopeHelper.DbHelper().GetScopeAndConfig(connection.ID, bpScope.ScopeId) | ||
if err != nil { | ||
return nil, err | ||
} | ||
// add board to scopes | ||
if utils.StringsContains(scopeConfig.Entities, plugin.DOMAIN_TYPE_TICKET) { | ||
scopeTicket := &ticket.Board{ | ||
DomainEntity: domainlayer.DomainEntity{ | ||
Id: didgen.NewDomainIdGenerator(&models.Service{}).Generate(connection.ID, service.Id), | ||
}, | ||
Name: service.Name, | ||
} | ||
scopes = append(scopes, scopeTicket) | ||
} | ||
} | ||
return scopes, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
/* | ||
Licensed to the Apache Software Foundation (ASF) under one or more | ||
contributor license agreements. See the NOTICE file distributed with | ||
this work for additional information regarding copyright ownership. | ||
The ASF licenses this file to You 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 api | ||
|
||
import ( | ||
"context" | ||
"net/http" | ||
|
||
"github.com/apache/incubator-devlake/core/errors" | ||
"github.com/apache/incubator-devlake/core/plugin" | ||
"github.com/apache/incubator-devlake/helpers/pluginhelper/api" | ||
"github.com/apache/incubator-devlake/plugins/opsgenie/models" | ||
) | ||
|
||
// @Summary test opsgenie connection | ||
// @Description Test Opsgenie Connection | ||
// @Tags plugins/opsgenie | ||
// @Param body body models.OpsgenieConn true "json body" | ||
// @Success 200 {object} shared.ApiBody "Success" | ||
// @Failure 400 {string} errcode.Error "Bad Request" | ||
// @Failure 500 {string} errcode.Error "Internal Error" | ||
// @Router /plugins/opsgenie/test [POST] | ||
func TestConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) { | ||
var connection models.OpsgenieConn | ||
|
||
err := api.Decode(input.Body, &connection, vld) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
apiClient, err := api.NewApiClientFromConnection(context.TODO(), basicRes, &connection) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// check API permissions | ||
response, err := apiClient.Get("v2/heartbeats/HeartbeatName/ping", nil, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if response.StatusCode == http.StatusUnauthorized { | ||
return nil, errors.HttpStatus(http.StatusUnauthorized).New("StatusUnauthorized error when testing api or read_api permissions") | ||
} | ||
|
||
if response.StatusCode == http.StatusUnprocessableEntity { | ||
return nil, errors.HttpStatus(http.StatusUnprocessableEntity).New("StatusUnprocessableEntity error when testing api") | ||
} | ||
|
||
if response.StatusCode == http.StatusForbidden { | ||
return nil, errors.HttpStatus(http.StatusForbidden).New("API Key need 'Read' and 'Configuration access' Access rights") | ||
} | ||
|
||
if response.StatusCode == http.StatusOK { | ||
return &plugin.ApiResourceOutput{Body: nil, Status: http.StatusOK}, nil | ||
} | ||
|
||
return &plugin.ApiResourceOutput{Body: nil, Status: response.StatusCode}, errors.HttpStatus(response.StatusCode).Wrap(err, "could not validate connection") | ||
} | ||
|
||
// @Summary create opsgenie connection | ||
// @Description Create Opsgenie connection | ||
// @Tags plugins/opsgenie | ||
// @Param body body models.OpsgenieConnection true "json body" | ||
// @Success 200 {object} models.OpsgenieConnection | ||
// @Failure 400 {string} errcode.Error "Bad Request" | ||
// @Failure 500 {string} errcode.Error "Internal Error" | ||
// @Router /plugins/opsgenie/connections [POST] | ||
func PostConnections(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) { | ||
connection := &models.OpsgenieConnection{} | ||
err := connectionHelper.Create(connection, input) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &plugin.ApiResourceOutput{Body: connection, Status: http.StatusOK}, nil | ||
} | ||
|
||
// @Summary patch opsgenie connection | ||
// @Description Patch Opsgenie connection | ||
// @Tags plugins/opsgenie | ||
// @Param body body models.OpsgenieConnection true "json body" | ||
// @Success 200 {object} models.OpsgenieConnection | ||
// @Failure 400 {string} errcode.Error "Bad Request" | ||
// @Failure 500 {string} errcode.Error "Internal Error" | ||
// @Router /plugins/opsgenie/connections/{connectionId} [PATCH] | ||
func PatchConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) { | ||
connection := &models.OpsgenieConnection{} | ||
err := connectionHelper.Patch(connection, input) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &plugin.ApiResourceOutput{Body: connection, Status: http.StatusOK}, nil | ||
} | ||
|
||
// @Summary delete opsgenie connection | ||
// @Description Delete Opsgenie connection | ||
// @Tags plugins/opsgenie | ||
// @Success 200 {object} models.OpsgenieConnection | ||
// @Failure 400 {string} errcode.Error "Bad Request" | ||
// @Failure 409 {object} services.BlueprintProjectPairs "References exist to this connection" | ||
// @Failure 500 {string} errcode.Error "Internal Error" | ||
// @Router /plugins/opsgenie/connections/{connectionId} [DELETE] | ||
func DeleteConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) { | ||
return connectionHelper.Delete(&models.OpsgenieConnection{}, input) | ||
} | ||
|
||
// @Summary list opsgenie connections | ||
// @Description List Opsgenie connections | ||
// @Tags plugins/opsgenie | ||
// @Success 200 {object} models.OpsgenieConnection | ||
// @Failure 400 {string} errcode.Error "Bad Request" | ||
// @Failure 500 {string} errcode.Error "Internal Error" | ||
// @Router /plugins/opsgenie/connections [GET] | ||
func ListConnections(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) { | ||
var connections []models.OpsgenieConnection | ||
err := connectionHelper.List(&connections) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return &plugin.ApiResourceOutput{Body: connections}, nil | ||
} | ||
|
||
// @Summary get opsgenie connection | ||
// @Description Get Opsgenie connection | ||
// @Tags plugins/opsgenie | ||
// @Success 200 {object} models.OpsgenieConnection | ||
// @Failure 400 {string} errcode.Error "Bad Request" | ||
// @Failure 500 {string} errcode.Error "Internal Error" | ||
// @Router /plugins/opsgenie/connections/{connectionId} [GET] | ||
func GetConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) { | ||
connection := &models.OpsgenieConnection{} | ||
err := connectionHelper.First(connection, input.Params) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &plugin.ApiResourceOutput{Body: connection}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* | ||
Licensed to the Apache Software Foundation (ASF) under one or more | ||
contributor license agreements. See the NOTICE file distributed with | ||
this work for additional information regarding copyright ownership. | ||
The ASF licenses this file to You 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 api | ||
|
||
import ( | ||
"github.com/apache/incubator-devlake/core/context" | ||
"github.com/apache/incubator-devlake/core/plugin" | ||
"github.com/apache/incubator-devlake/helpers/pluginhelper/api" | ||
"github.com/apache/incubator-devlake/plugins/opsgenie/models" | ||
"github.com/go-playground/validator/v10" | ||
) | ||
|
||
var vld *validator.Validate | ||
var connectionHelper *api.ConnectionApiHelper | ||
|
||
var scopeHelper *api.ScopeApiHelper[models.OpsgenieConnection, models.Service, models.OpsenieScopeConfig] | ||
|
||
var basicRes context.BasicRes | ||
|
||
func Init(br context.BasicRes, p plugin.PluginMeta) { | ||
|
||
basicRes = br | ||
vld = validator.New() | ||
connectionHelper = api.NewConnectionHelper( | ||
basicRes, | ||
vld, | ||
p.Name(), | ||
) | ||
params := &api.ReflectionParameters{ | ||
ScopeIdFieldName: "Id", | ||
ScopeIdColumnName: "id", | ||
RawScopeParamName: "ScopeId", | ||
SearchScopeParamName: "name", | ||
} | ||
scopeHelper = api.NewScopeHelper[models.OpsgenieConnection, models.Service, models.OpsenieScopeConfig]( | ||
basicRes, | ||
vld, | ||
connectionHelper, | ||
api.NewScopeDatabaseHelperImpl[models.OpsgenieConnection, models.Service, models.OpsenieScopeConfig]( | ||
basicRes, connectionHelper, params), | ||
params, | ||
&api.ScopeHelperOptions{}, | ||
) | ||
} |
Oops, something went wrong.