github.com/weaviate/weaviate@v1.24.6/adapters/handlers/rest/handlers_schema.go (about)

     1  //                           _       _
     2  // __      _____  __ ___   ___  __ _| |_ ___
     3  // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
     4  //  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
     5  //   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
     6  //
     7  //  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
     8  //
     9  //  CONTACT: hello@weaviate.io
    10  //
    11  
    12  package rest
    13  
    14  import (
    15  	"github.com/go-openapi/runtime/middleware"
    16  	"github.com/sirupsen/logrus"
    17  	"github.com/weaviate/weaviate/adapters/handlers/rest/operations"
    18  	"github.com/weaviate/weaviate/adapters/handlers/rest/operations/schema"
    19  	"github.com/weaviate/weaviate/entities/models"
    20  	"github.com/weaviate/weaviate/usecases/auth/authorization/errors"
    21  	"github.com/weaviate/weaviate/usecases/monitoring"
    22  	uco "github.com/weaviate/weaviate/usecases/objects"
    23  	schemaUC "github.com/weaviate/weaviate/usecases/schema"
    24  )
    25  
    26  type schemaHandlers struct {
    27  	manager             *schemaUC.Manager
    28  	metricRequestsTotal restApiRequestsTotal
    29  }
    30  
    31  func (s *schemaHandlers) addClass(params schema.SchemaObjectsCreateParams,
    32  	principal *models.Principal,
    33  ) middleware.Responder {
    34  	err := s.manager.AddClass(params.HTTPRequest.Context(), principal, params.ObjectClass)
    35  	if err != nil {
    36  		s.metricRequestsTotal.logError(params.ObjectClass.Class, err)
    37  		switch err.(type) {
    38  		case errors.Forbidden:
    39  			return schema.NewSchemaObjectsCreateForbidden().
    40  				WithPayload(errPayloadFromSingleErr(err))
    41  		default:
    42  			return schema.NewSchemaObjectsCreateUnprocessableEntity().
    43  				WithPayload(errPayloadFromSingleErr(err))
    44  		}
    45  	}
    46  
    47  	s.metricRequestsTotal.logOk(params.ObjectClass.Class)
    48  	return schema.NewSchemaObjectsCreateOK().WithPayload(params.ObjectClass)
    49  }
    50  
    51  func (s *schemaHandlers) updateClass(params schema.SchemaObjectsUpdateParams,
    52  	principal *models.Principal,
    53  ) middleware.Responder {
    54  	err := s.manager.UpdateClass(params.HTTPRequest.Context(), principal, params.ClassName,
    55  		params.ObjectClass)
    56  	if err != nil {
    57  		s.metricRequestsTotal.logError(params.ClassName, err)
    58  		if err == schemaUC.ErrNotFound {
    59  			return schema.NewSchemaObjectsUpdateNotFound()
    60  		}
    61  
    62  		switch err.(type) {
    63  		case errors.Forbidden:
    64  			return schema.NewSchemaObjectsUpdateForbidden().
    65  				WithPayload(errPayloadFromSingleErr(err))
    66  		default:
    67  			return schema.NewSchemaObjectsUpdateUnprocessableEntity().
    68  				WithPayload(errPayloadFromSingleErr(err))
    69  		}
    70  	}
    71  
    72  	s.metricRequestsTotal.logOk(params.ClassName)
    73  	return schema.NewSchemaObjectsUpdateOK().WithPayload(params.ObjectClass)
    74  }
    75  
    76  func (s *schemaHandlers) getClass(params schema.SchemaObjectsGetParams,
    77  	principal *models.Principal,
    78  ) middleware.Responder {
    79  	class, err := s.manager.GetClass(params.HTTPRequest.Context(), principal, params.ClassName)
    80  	if err != nil {
    81  		s.metricRequestsTotal.logError(params.ClassName, err)
    82  		switch err.(type) {
    83  		case errors.Forbidden:
    84  			return schema.NewSchemaObjectsGetForbidden().
    85  				WithPayload(errPayloadFromSingleErr(err))
    86  		default:
    87  			return schema.NewSchemaObjectsGetInternalServerError().
    88  				WithPayload(errPayloadFromSingleErr(err))
    89  		}
    90  	}
    91  
    92  	if class == nil {
    93  		s.metricRequestsTotal.logUserError(params.ClassName)
    94  		return schema.NewSchemaObjectsGetNotFound()
    95  	}
    96  
    97  	s.metricRequestsTotal.logOk(params.ClassName)
    98  	return schema.NewSchemaObjectsGetOK().WithPayload(class)
    99  }
   100  
   101  func (s *schemaHandlers) deleteClass(params schema.SchemaObjectsDeleteParams, principal *models.Principal) middleware.Responder {
   102  	err := s.manager.DeleteClass(params.HTTPRequest.Context(), principal, params.ClassName)
   103  	if err != nil {
   104  		s.metricRequestsTotal.logError(params.ClassName, err)
   105  		switch err.(type) {
   106  		case errors.Forbidden:
   107  			return schema.NewSchemaObjectsDeleteForbidden().
   108  				WithPayload(errPayloadFromSingleErr(err))
   109  		default:
   110  			return schema.NewSchemaObjectsDeleteBadRequest().WithPayload(errPayloadFromSingleErr(err))
   111  		}
   112  	}
   113  
   114  	s.metricRequestsTotal.logOk(params.ClassName)
   115  	return schema.NewSchemaObjectsDeleteOK()
   116  }
   117  
   118  func (s *schemaHandlers) addClassProperty(params schema.SchemaObjectsPropertiesAddParams,
   119  	principal *models.Principal,
   120  ) middleware.Responder {
   121  	err := s.manager.AddClassProperty(params.HTTPRequest.Context(), principal, params.ClassName, params.Body)
   122  	if err != nil {
   123  		s.metricRequestsTotal.logError(params.ClassName, err)
   124  		switch err.(type) {
   125  		case errors.Forbidden:
   126  			return schema.NewSchemaObjectsPropertiesAddForbidden().
   127  				WithPayload(errPayloadFromSingleErr(err))
   128  		default:
   129  			return schema.NewSchemaObjectsPropertiesAddUnprocessableEntity().
   130  				WithPayload(errPayloadFromSingleErr(err))
   131  		}
   132  	}
   133  
   134  	s.metricRequestsTotal.logOk(params.ClassName)
   135  	return schema.NewSchemaObjectsPropertiesAddOK().WithPayload(params.Body)
   136  }
   137  
   138  func (s *schemaHandlers) getSchema(params schema.SchemaDumpParams, principal *models.Principal) middleware.Responder {
   139  	dbSchema, err := s.manager.GetSchema(principal)
   140  	if err != nil {
   141  		s.metricRequestsTotal.logError("", err)
   142  		switch err.(type) {
   143  		case errors.Forbidden:
   144  			return schema.NewSchemaDumpForbidden().
   145  				WithPayload(errPayloadFromSingleErr(err))
   146  		default:
   147  			return schema.NewSchemaDumpForbidden().WithPayload(errPayloadFromSingleErr(err))
   148  		}
   149  	}
   150  
   151  	payload := dbSchema.Objects
   152  
   153  	s.metricRequestsTotal.logOk("")
   154  	return schema.NewSchemaDumpOK().WithPayload(payload)
   155  }
   156  
   157  func (s *schemaHandlers) getClusterStatus(params schema.SchemaClusterStatusParams, principal *models.Principal) middleware.Responder {
   158  	status, err := s.manager.ClusterStatus(params.HTTPRequest.Context())
   159  	if err == nil {
   160  		s.metricRequestsTotal.logOk("")
   161  		return schema.NewSchemaClusterStatusOK().WithPayload(status)
   162  	} else {
   163  		s.metricRequestsTotal.logServerError("", err)
   164  		return schema.NewSchemaClusterStatusInternalServerError().WithPayload(status)
   165  	}
   166  }
   167  
   168  func (s *schemaHandlers) getShardsStatus(params schema.SchemaObjectsShardsGetParams,
   169  	principal *models.Principal,
   170  ) middleware.Responder {
   171  	var tenant string
   172  	if params.Tenant == nil {
   173  		tenant = ""
   174  	} else {
   175  		tenant = *params.Tenant
   176  	}
   177  	status, err := s.manager.GetShardsStatus(params.HTTPRequest.Context(), principal, params.ClassName, tenant)
   178  	if err != nil {
   179  		s.metricRequestsTotal.logError("", err)
   180  		switch err.(type) {
   181  		case errors.Forbidden:
   182  			return schema.NewSchemaObjectsShardsGetForbidden().
   183  				WithPayload(errPayloadFromSingleErr(err))
   184  		default:
   185  			return schema.NewSchemaObjectsShardsGetNotFound().
   186  				WithPayload(errPayloadFromSingleErr(err))
   187  		}
   188  	}
   189  
   190  	payload := status
   191  
   192  	s.metricRequestsTotal.logOk("")
   193  	return schema.NewSchemaObjectsShardsGetOK().WithPayload(payload)
   194  }
   195  
   196  func (s *schemaHandlers) updateShardStatus(params schema.SchemaObjectsShardsUpdateParams,
   197  	principal *models.Principal,
   198  ) middleware.Responder {
   199  	err := s.manager.UpdateShardStatus(
   200  		params.HTTPRequest.Context(), principal, params.ClassName, params.ShardName, params.Body.Status)
   201  	if err != nil {
   202  		s.metricRequestsTotal.logError("", err)
   203  		switch err.(type) {
   204  		case errors.Forbidden:
   205  			return schema.NewSchemaObjectsShardsGetForbidden().
   206  				WithPayload(errPayloadFromSingleErr(err))
   207  		default:
   208  			return schema.NewSchemaObjectsShardsUpdateUnprocessableEntity().
   209  				WithPayload(errPayloadFromSingleErr(err))
   210  		}
   211  	}
   212  
   213  	payload := params.Body
   214  
   215  	s.metricRequestsTotal.logOk("")
   216  	return schema.NewSchemaObjectsShardsUpdateOK().WithPayload(payload)
   217  }
   218  
   219  func (s *schemaHandlers) createTenants(params schema.TenantsCreateParams,
   220  	principal *models.Principal,
   221  ) middleware.Responder {
   222  	created, err := s.manager.AddTenants(
   223  		params.HTTPRequest.Context(), principal, params.ClassName, params.Body)
   224  	if err != nil {
   225  		s.metricRequestsTotal.logError(params.ClassName, err)
   226  		switch err.(type) {
   227  		case errors.Forbidden:
   228  			return schema.NewTenantsCreateForbidden().
   229  				WithPayload(errPayloadFromSingleErr(err))
   230  		default:
   231  			return schema.NewTenantsCreateUnprocessableEntity().
   232  				WithPayload(errPayloadFromSingleErr(err))
   233  		}
   234  	}
   235  
   236  	s.metricRequestsTotal.logOk(params.ClassName)
   237  	return schema.NewTenantsCreateOK().WithPayload(created)
   238  }
   239  
   240  func (s *schemaHandlers) updateTenants(params schema.TenantsUpdateParams,
   241  	principal *models.Principal,
   242  ) middleware.Responder {
   243  	err := s.manager.UpdateTenants(
   244  		params.HTTPRequest.Context(), principal, params.ClassName, params.Body)
   245  	if err != nil {
   246  		s.metricRequestsTotal.logError(params.ClassName, err)
   247  		switch err.(type) {
   248  		case errors.Forbidden:
   249  			return schema.NewTenantsUpdateForbidden().
   250  				WithPayload(errPayloadFromSingleErr(err))
   251  		default:
   252  			return schema.NewTenantsUpdateUnprocessableEntity().
   253  				WithPayload(errPayloadFromSingleErr(err))
   254  		}
   255  	}
   256  
   257  	payload := params.Body
   258  
   259  	s.metricRequestsTotal.logOk(params.ClassName)
   260  	return schema.NewTenantsUpdateOK().WithPayload(payload)
   261  }
   262  
   263  func (s *schemaHandlers) deleteTenants(params schema.TenantsDeleteParams,
   264  	principal *models.Principal,
   265  ) middleware.Responder {
   266  	err := s.manager.DeleteTenants(
   267  		params.HTTPRequest.Context(), principal, params.ClassName, params.Tenants)
   268  	if err != nil {
   269  		s.metricRequestsTotal.logError(params.ClassName, err)
   270  		switch err.(type) {
   271  		case errors.Forbidden:
   272  			return schema.NewTenantsDeleteForbidden().
   273  				WithPayload(errPayloadFromSingleErr(err))
   274  		default:
   275  			return schema.NewTenantsDeleteUnprocessableEntity().
   276  				WithPayload(errPayloadFromSingleErr(err))
   277  		}
   278  	}
   279  
   280  	s.metricRequestsTotal.logOk(params.ClassName)
   281  	return schema.NewTenantsDeleteOK()
   282  }
   283  
   284  func (s *schemaHandlers) getTenants(params schema.TenantsGetParams,
   285  	principal *models.Principal,
   286  ) middleware.Responder {
   287  	tenants, err := s.manager.GetTenants(params.HTTPRequest.Context(), principal, params.ClassName)
   288  	if err != nil {
   289  		s.metricRequestsTotal.logError(params.ClassName, err)
   290  		switch err.(type) {
   291  		case errors.Forbidden:
   292  			return schema.NewTenantsGetForbidden().
   293  				WithPayload(errPayloadFromSingleErr(err))
   294  		default:
   295  			return schema.NewTenantsGetUnprocessableEntity().
   296  				WithPayload(errPayloadFromSingleErr(err))
   297  		}
   298  	}
   299  
   300  	s.metricRequestsTotal.logOk(params.ClassName)
   301  	return schema.NewTenantsGetOK().WithPayload(tenants)
   302  }
   303  
   304  func setupSchemaHandlers(api *operations.WeaviateAPI, manager *schemaUC.Manager, metrics *monitoring.PrometheusMetrics, logger logrus.FieldLogger) {
   305  	h := &schemaHandlers{manager, newSchemaRequestsTotal(metrics, logger)}
   306  
   307  	api.SchemaSchemaObjectsCreateHandler = schema.
   308  		SchemaObjectsCreateHandlerFunc(h.addClass)
   309  	api.SchemaSchemaObjectsDeleteHandler = schema.
   310  		SchemaObjectsDeleteHandlerFunc(h.deleteClass)
   311  	api.SchemaSchemaObjectsPropertiesAddHandler = schema.
   312  		SchemaObjectsPropertiesAddHandlerFunc(h.addClassProperty)
   313  
   314  	api.SchemaSchemaObjectsUpdateHandler = schema.
   315  		SchemaObjectsUpdateHandlerFunc(h.updateClass)
   316  
   317  	api.SchemaSchemaObjectsGetHandler = schema.
   318  		SchemaObjectsGetHandlerFunc(h.getClass)
   319  	api.SchemaSchemaDumpHandler = schema.
   320  		SchemaDumpHandlerFunc(h.getSchema)
   321  	api.SchemaSchemaClusterStatusHandler = schema.
   322  		SchemaClusterStatusHandlerFunc(h.getClusterStatus)
   323  
   324  	api.SchemaSchemaObjectsShardsGetHandler = schema.
   325  		SchemaObjectsShardsGetHandlerFunc(h.getShardsStatus)
   326  	api.SchemaSchemaObjectsShardsUpdateHandler = schema.
   327  		SchemaObjectsShardsUpdateHandlerFunc(h.updateShardStatus)
   328  
   329  	api.SchemaTenantsCreateHandler = schema.TenantsCreateHandlerFunc(h.createTenants)
   330  	api.SchemaTenantsUpdateHandler = schema.TenantsUpdateHandlerFunc(h.updateTenants)
   331  	api.SchemaTenantsDeleteHandler = schema.TenantsDeleteHandlerFunc(h.deleteTenants)
   332  	api.SchemaTenantsGetHandler = schema.TenantsGetHandlerFunc(h.getTenants)
   333  }
   334  
   335  type schemaRequestsTotal struct {
   336  	*restApiRequestsTotalImpl
   337  }
   338  
   339  func newSchemaRequestsTotal(metrics *monitoring.PrometheusMetrics, logger logrus.FieldLogger) restApiRequestsTotal {
   340  	return &schemaRequestsTotal{
   341  		restApiRequestsTotalImpl: &restApiRequestsTotalImpl{newRequestsTotalMetric(metrics, "rest"), "rest", "schema", logger},
   342  	}
   343  }
   344  
   345  func (e *schemaRequestsTotal) logError(className string, err error) {
   346  	switch err.(type) {
   347  	case uco.ErrMultiTenancy:
   348  		e.logUserError(className)
   349  	case errors.Forbidden:
   350  		e.logUserError(className)
   351  	default:
   352  		e.logUserError(className)
   353  	}
   354  }