images.go 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145
  1. package server
  2. import (
  3. "bytes"
  4. "cmp"
  5. "context"
  6. "crypto/sha256"
  7. "encoding/base64"
  8. "encoding/hex"
  9. "encoding/json"
  10. "errors"
  11. "fmt"
  12. "io"
  13. "log"
  14. "log/slog"
  15. "net/http"
  16. "net/url"
  17. "os"
  18. "path/filepath"
  19. "runtime"
  20. "strconv"
  21. "strings"
  22. "golang.org/x/exp/slices"
  23. "github.com/ollama/ollama/api"
  24. "github.com/ollama/ollama/auth"
  25. "github.com/ollama/ollama/format"
  26. "github.com/ollama/ollama/llm"
  27. "github.com/ollama/ollama/types/errtypes"
  28. "github.com/ollama/ollama/types/model"
  29. "github.com/ollama/ollama/version"
  30. )
  31. type registryOptions struct {
  32. Insecure bool
  33. Username string
  34. Password string
  35. Token string
  36. }
  37. type Model struct {
  38. Name string `json:"name"`
  39. Config ConfigV2
  40. ShortName string
  41. ModelPath string
  42. ParentModel string
  43. AdapterPaths []string
  44. ProjectorPaths []string
  45. Template string
  46. System string
  47. License []string
  48. Digest string
  49. Size int64
  50. Options map[string]interface{}
  51. Messages []Message
  52. }
  53. func (m *Model) IsEmbedding() bool {
  54. return slices.Contains(m.Config.ModelFamilies, "bert") || slices.Contains(m.Config.ModelFamilies, "nomic-bert")
  55. }
  56. func (m *Model) String() string {
  57. var modelfile model.File
  58. modelfile.Commands = append(modelfile.Commands, model.Command{
  59. Name: "model",
  60. Args: m.ModelPath,
  61. })
  62. if m.Template != "" {
  63. modelfile.Commands = append(modelfile.Commands, model.Command{
  64. Name: "template",
  65. Args: m.Template,
  66. })
  67. }
  68. if m.System != "" {
  69. modelfile.Commands = append(modelfile.Commands, model.Command{
  70. Name: "system",
  71. Args: m.System,
  72. })
  73. }
  74. for _, adapter := range m.AdapterPaths {
  75. modelfile.Commands = append(modelfile.Commands, model.Command{
  76. Name: "adapter",
  77. Args: adapter,
  78. })
  79. }
  80. for _, projector := range m.ProjectorPaths {
  81. modelfile.Commands = append(modelfile.Commands, model.Command{
  82. Name: "projector",
  83. Args: projector,
  84. })
  85. }
  86. for k, v := range m.Options {
  87. switch v := v.(type) {
  88. case []any:
  89. for _, s := range v {
  90. modelfile.Commands = append(modelfile.Commands, model.Command{
  91. Name: k,
  92. Args: fmt.Sprintf("%v", s),
  93. })
  94. }
  95. default:
  96. modelfile.Commands = append(modelfile.Commands, model.Command{
  97. Name: k,
  98. Args: fmt.Sprintf("%v", v),
  99. })
  100. }
  101. }
  102. for _, license := range m.License {
  103. modelfile.Commands = append(modelfile.Commands, model.Command{
  104. Name: "license",
  105. Args: license,
  106. })
  107. }
  108. for _, msg := range m.Messages {
  109. modelfile.Commands = append(modelfile.Commands, model.Command{
  110. Name: "message",
  111. Args: fmt.Sprintf("%s %s", msg.Role, msg.Content),
  112. })
  113. }
  114. return modelfile.String()
  115. }
  116. type Message struct {
  117. Role string `json:"role"`
  118. Content string `json:"content"`
  119. }
  120. type ManifestV2 struct {
  121. SchemaVersion int `json:"schemaVersion"`
  122. MediaType string `json:"mediaType"`
  123. Config *Layer `json:"config"`
  124. Layers []*Layer `json:"layers"`
  125. }
  126. type ConfigV2 struct {
  127. ModelFormat string `json:"model_format"`
  128. ModelFamily string `json:"model_family"`
  129. ModelFamilies []string `json:"model_families"`
  130. ModelType string `json:"model_type"`
  131. FileType string `json:"file_type"`
  132. // required by spec
  133. Architecture string `json:"architecture"`
  134. OS string `json:"os"`
  135. RootFS RootFS `json:"rootfs"`
  136. }
  137. type RootFS struct {
  138. Type string `json:"type"`
  139. DiffIDs []string `json:"diff_ids"`
  140. }
  141. func (m *ManifestV2) GetTotalSize() (total int64) {
  142. for _, layer := range m.Layers {
  143. total += layer.Size
  144. }
  145. total += m.Config.Size
  146. return total
  147. }
  148. func GetManifest(mp ModelPath) (*ManifestV2, string, error) {
  149. fp, err := mp.GetManifestPath()
  150. if err != nil {
  151. return nil, "", err
  152. }
  153. if _, err = os.Stat(fp); err != nil {
  154. return nil, "", err
  155. }
  156. var manifest *ManifestV2
  157. bts, err := os.ReadFile(fp)
  158. if err != nil {
  159. return nil, "", fmt.Errorf("couldn't open file '%s'", fp)
  160. }
  161. shaSum := sha256.Sum256(bts)
  162. shaStr := hex.EncodeToString(shaSum[:])
  163. if err := json.Unmarshal(bts, &manifest); err != nil {
  164. return nil, "", err
  165. }
  166. return manifest, shaStr, nil
  167. }
  168. func GetModel(name string) (*Model, error) {
  169. mp := ParseModelPath(name)
  170. manifest, digest, err := GetManifest(mp)
  171. if err != nil {
  172. return nil, err
  173. }
  174. model := &Model{
  175. Name: mp.GetFullTagname(),
  176. ShortName: mp.GetShortTagname(),
  177. Digest: digest,
  178. Template: "{{ .Prompt }}",
  179. License: []string{},
  180. Size: manifest.GetTotalSize(),
  181. }
  182. filename, err := GetBlobsPath(manifest.Config.Digest)
  183. if err != nil {
  184. return nil, err
  185. }
  186. configFile, err := os.Open(filename)
  187. if err != nil {
  188. return nil, err
  189. }
  190. defer configFile.Close()
  191. if err := json.NewDecoder(configFile).Decode(&model.Config); err != nil {
  192. return nil, err
  193. }
  194. for _, layer := range manifest.Layers {
  195. filename, err := GetBlobsPath(layer.Digest)
  196. if err != nil {
  197. return nil, err
  198. }
  199. switch layer.MediaType {
  200. case "application/vnd.ollama.image.model":
  201. model.ModelPath = filename
  202. model.ParentModel = layer.From
  203. case "application/vnd.ollama.image.embed":
  204. // Deprecated in versions > 0.1.2
  205. // TODO: remove this warning in a future version
  206. slog.Info("WARNING: model contains embeddings, but embeddings in modelfiles have been deprecated and will be ignored.")
  207. case "application/vnd.ollama.image.adapter":
  208. model.AdapterPaths = append(model.AdapterPaths, filename)
  209. case "application/vnd.ollama.image.projector":
  210. model.ProjectorPaths = append(model.ProjectorPaths, filename)
  211. case "application/vnd.ollama.image.template":
  212. bts, err := os.ReadFile(filename)
  213. if err != nil {
  214. return nil, err
  215. }
  216. model.Template = string(bts)
  217. case "application/vnd.ollama.image.system":
  218. bts, err := os.ReadFile(filename)
  219. if err != nil {
  220. return nil, err
  221. }
  222. model.System = string(bts)
  223. case "application/vnd.ollama.image.prompt":
  224. bts, err := os.ReadFile(filename)
  225. if err != nil {
  226. return nil, err
  227. }
  228. model.Template = string(bts)
  229. case "application/vnd.ollama.image.params":
  230. params, err := os.Open(filename)
  231. if err != nil {
  232. return nil, err
  233. }
  234. defer params.Close()
  235. // parse model options parameters into a map so that we can see which fields have been specified explicitly
  236. if err = json.NewDecoder(params).Decode(&model.Options); err != nil {
  237. return nil, err
  238. }
  239. case "application/vnd.ollama.image.messages":
  240. msgs, err := os.Open(filename)
  241. if err != nil {
  242. return nil, err
  243. }
  244. defer msgs.Close()
  245. if err = json.NewDecoder(msgs).Decode(&model.Messages); err != nil {
  246. return nil, err
  247. }
  248. case "application/vnd.ollama.image.license":
  249. bts, err := os.ReadFile(filename)
  250. if err != nil {
  251. return nil, err
  252. }
  253. model.License = append(model.License, string(bts))
  254. }
  255. }
  256. return model, nil
  257. }
  258. func realpath(rel, from string) string {
  259. abspath, err := filepath.Abs(from)
  260. if err != nil {
  261. return from
  262. }
  263. home, err := os.UserHomeDir()
  264. if err != nil {
  265. return abspath
  266. }
  267. if from == "~" {
  268. return home
  269. } else if strings.HasPrefix(from, "~/") {
  270. return filepath.Join(home, from[2:])
  271. }
  272. if _, err := os.Stat(filepath.Join(rel, from)); err == nil {
  273. // this is a file relative to the Modelfile
  274. return filepath.Join(rel, from)
  275. }
  276. return abspath
  277. }
  278. func CreateModel(ctx context.Context, name, modelFileDir, quantization string, modelfile *model.File, fn func(resp api.ProgressResponse)) (err error) {
  279. config := ConfigV2{
  280. OS: "linux",
  281. Architecture: "amd64",
  282. RootFS: RootFS{
  283. Type: "layers",
  284. },
  285. }
  286. var messages []*api.Message
  287. parameters := make(map[string]any)
  288. var layers []*Layer
  289. for _, c := range modelfile.Commands {
  290. mediatype := fmt.Sprintf("application/vnd.ollama.image.%s", c.Name)
  291. switch c.Name {
  292. case "model", "adapter":
  293. var baseLayers []*layerWithGGML
  294. if name := model.ParseName(c.Args); name.IsValid() {
  295. baseLayers, err = parseFromModel(ctx, name, fn)
  296. if err != nil {
  297. return err
  298. }
  299. } else if strings.HasPrefix(c.Args, "@") {
  300. blobpath, err := GetBlobsPath(strings.TrimPrefix(c.Args, "@"))
  301. if err != nil {
  302. return err
  303. }
  304. blob, err := os.Open(blobpath)
  305. if err != nil {
  306. return err
  307. }
  308. defer blob.Close()
  309. baseLayers, err = parseFromFile(ctx, blob, fn)
  310. if err != nil {
  311. return err
  312. }
  313. } else if file, err := os.Open(realpath(modelFileDir, c.Args)); err == nil {
  314. defer file.Close()
  315. baseLayers, err = parseFromFile(ctx, file, fn)
  316. if err != nil {
  317. return err
  318. }
  319. } else {
  320. return fmt.Errorf("invalid model reference: %s", c.Args)
  321. }
  322. for _, baseLayer := range baseLayers {
  323. if quantization != "" && baseLayer.GGML != nil && baseLayer.GGML.Name() == "gguf" {
  324. ftype, err := llm.ParseFileType(quantization)
  325. if err != nil {
  326. return err
  327. }
  328. filetype := baseLayer.GGML.KV().FileType()
  329. if !slices.Contains([]string{"F16", "F32"}, filetype) {
  330. return errors.New("quantization is only supported for F16 and F32 models")
  331. }
  332. fn(api.ProgressResponse{Status: fmt.Sprintf("quantizing %s model to %s", filetype, quantization)})
  333. blob, err := GetBlobsPath(baseLayer.Digest)
  334. if err != nil {
  335. return err
  336. }
  337. temp, err := os.CreateTemp(filepath.Dir(blob), quantization)
  338. if err != nil {
  339. return err
  340. }
  341. defer temp.Close()
  342. defer os.Remove(temp.Name())
  343. if err := llm.Quantize(blob, temp.Name(), ftype); err != nil {
  344. return err
  345. }
  346. baseLayer.Layer, err = NewLayer(temp, baseLayer.Layer.MediaType)
  347. if err != nil {
  348. return err
  349. }
  350. }
  351. if baseLayer.GGML != nil {
  352. config.ModelFormat = cmp.Or(config.ModelFormat, baseLayer.GGML.Name())
  353. config.ModelFamily = cmp.Or(config.ModelFamily, baseLayer.GGML.KV().Architecture())
  354. config.ModelType = cmp.Or(config.ModelType, format.HumanNumber(baseLayer.GGML.KV().ParameterCount()))
  355. config.FileType = cmp.Or(config.FileType, baseLayer.GGML.KV().FileType())
  356. config.ModelFamilies = append(config.ModelFamilies, baseLayer.GGML.KV().Architecture())
  357. }
  358. layers = append(layers, baseLayer.Layer)
  359. }
  360. case "license", "template", "system":
  361. blob := strings.NewReader(c.Args)
  362. layer, err := NewLayer(blob, mediatype)
  363. if err != nil {
  364. return err
  365. }
  366. if c.Name != "license" {
  367. // replace
  368. layers = slices.DeleteFunc(layers, func(layer *Layer) bool {
  369. return layer.MediaType == mediatype
  370. })
  371. }
  372. layers = append(layers, layer)
  373. case "message":
  374. role, content, ok := strings.Cut(c.Args, ": ")
  375. if !ok {
  376. return fmt.Errorf("invalid message: %s", c.Args)
  377. }
  378. messages = append(messages, &api.Message{Role: role, Content: content})
  379. default:
  380. ps, err := api.FormatParams(map[string][]string{c.Name: {c.Args}})
  381. if err != nil {
  382. return err
  383. }
  384. for k, v := range ps {
  385. if ks, ok := parameters[k].([]string); ok {
  386. parameters[k] = append(ks, v.([]string)...)
  387. } else if vs, ok := v.([]string); ok {
  388. parameters[k] = vs
  389. } else {
  390. parameters[k] = v
  391. }
  392. }
  393. }
  394. }
  395. var err2 error
  396. layers = slices.DeleteFunc(layers, func(layer *Layer) bool {
  397. switch layer.MediaType {
  398. case "application/vnd.ollama.image.message":
  399. // if there are new messages, remove the inherited ones
  400. if len(messages) > 0 {
  401. return true
  402. }
  403. return false
  404. case "application/vnd.ollama.image.params":
  405. // merge inherited parameters with new ones
  406. r, err := layer.Open()
  407. if err != nil {
  408. err2 = err
  409. return false
  410. }
  411. defer r.Close()
  412. var ps map[string]any
  413. if err := json.NewDecoder(r).Decode(&ps); err != nil {
  414. err2 = err
  415. return false
  416. }
  417. for k, v := range ps {
  418. if _, ok := parameters[k]; !ok {
  419. parameters[k] = v
  420. }
  421. }
  422. return true
  423. default:
  424. return false
  425. }
  426. })
  427. if err2 != nil {
  428. return err2
  429. }
  430. if len(messages) > 0 {
  431. var b bytes.Buffer
  432. if err := json.NewEncoder(&b).Encode(messages); err != nil {
  433. return err
  434. }
  435. layer, err := NewLayer(&b, "application/vnd.ollama.image.messages")
  436. if err != nil {
  437. return err
  438. }
  439. layers = append(layers, layer)
  440. }
  441. if len(parameters) > 0 {
  442. var b bytes.Buffer
  443. if err := json.NewEncoder(&b).Encode(parameters); err != nil {
  444. return err
  445. }
  446. layer, err := NewLayer(&b, "application/vnd.ollama.image.params")
  447. if err != nil {
  448. return err
  449. }
  450. layers = append(layers, layer)
  451. }
  452. digests := make([]string, len(layers))
  453. for i, layer := range layers {
  454. digests[i] = layer.Digest
  455. }
  456. config.RootFS.DiffIDs = digests
  457. var b bytes.Buffer
  458. if err := json.NewEncoder(&b).Encode(config); err != nil {
  459. return err
  460. }
  461. layer, err := NewLayer(&b, "application/vnd.docker.container.image.v1+json")
  462. if err != nil {
  463. return err
  464. }
  465. for _, layer := range append(layers, layer) {
  466. if layer.status != "" {
  467. fn(api.ProgressResponse{Status: layer.status})
  468. }
  469. }
  470. unref := make(map[string]struct{})
  471. if manifest, _, err := GetManifest(ParseModelPath(name)); err == nil {
  472. for _, layer := range manifest.Layers {
  473. if !slices.Contains(digests, layer.Digest) {
  474. unref[layer.Digest] = struct{}{}
  475. }
  476. }
  477. if manifest.Config.Digest != layer.Digest {
  478. unref[manifest.Config.Digest] = struct{}{}
  479. }
  480. }
  481. fn(api.ProgressResponse{Status: "writing manifest"})
  482. if err := WriteManifest(name, layer, layers); err != nil {
  483. return err
  484. }
  485. if os.Getenv("OLLAMA_NOPRUNE") == "" && len(unref) > 0 {
  486. fn(api.ProgressResponse{Status: "removing unused layers"})
  487. if err := deleteUnusedLayers(nil, unref, false); err != nil {
  488. return err
  489. }
  490. }
  491. fn(api.ProgressResponse{Status: "success"})
  492. return nil
  493. }
  494. func CopyModel(src, dst model.Name) error {
  495. if !dst.IsFullyQualified() {
  496. return model.Unqualified(dst)
  497. }
  498. if !src.IsFullyQualified() {
  499. return model.Unqualified(src)
  500. }
  501. if src.Filepath() == dst.Filepath() {
  502. return nil
  503. }
  504. manifests, err := GetManifestPath()
  505. if err != nil {
  506. return err
  507. }
  508. dstpath := filepath.Join(manifests, dst.Filepath())
  509. if err := os.MkdirAll(filepath.Dir(dstpath), 0o755); err != nil {
  510. return err
  511. }
  512. srcpath := filepath.Join(manifests, src.Filepath())
  513. srcfile, err := os.Open(srcpath)
  514. if err != nil {
  515. return err
  516. }
  517. defer srcfile.Close()
  518. dstfile, err := os.Create(dstpath)
  519. if err != nil {
  520. return err
  521. }
  522. defer dstfile.Close()
  523. _, err = io.Copy(dstfile, srcfile)
  524. return err
  525. }
  526. func deleteUnusedLayers(skipModelPath *ModelPath, deleteMap map[string]struct{}, dryRun bool) error {
  527. fp, err := GetManifestPath()
  528. if err != nil {
  529. return err
  530. }
  531. walkFunc := func(path string, info os.FileInfo, _ error) error {
  532. if info.IsDir() {
  533. return nil
  534. }
  535. dir, file := filepath.Split(path)
  536. dir = strings.Trim(strings.TrimPrefix(dir, fp), string(os.PathSeparator))
  537. tag := strings.Join([]string{dir, file}, ":")
  538. fmp := ParseModelPath(tag)
  539. // skip the manifest we're trying to delete
  540. if skipModelPath != nil && skipModelPath.GetFullTagname() == fmp.GetFullTagname() {
  541. return nil
  542. }
  543. // save (i.e. delete from the deleteMap) any files used in other manifests
  544. manifest, _, err := GetManifest(fmp)
  545. if err != nil {
  546. // nolint: nilerr
  547. return nil
  548. }
  549. for _, layer := range manifest.Layers {
  550. delete(deleteMap, layer.Digest)
  551. }
  552. delete(deleteMap, manifest.Config.Digest)
  553. return nil
  554. }
  555. if err := filepath.Walk(fp, walkFunc); err != nil {
  556. return err
  557. }
  558. // only delete the files which are still in the deleteMap
  559. for k := range deleteMap {
  560. fp, err := GetBlobsPath(k)
  561. if err != nil {
  562. slog.Info(fmt.Sprintf("couldn't get file path for '%s': %v", k, err))
  563. continue
  564. }
  565. if !dryRun {
  566. if err := os.Remove(fp); err != nil {
  567. slog.Info(fmt.Sprintf("couldn't remove file '%s': %v", fp, err))
  568. continue
  569. }
  570. } else {
  571. slog.Info(fmt.Sprintf("wanted to remove: %s", fp))
  572. }
  573. }
  574. return nil
  575. }
  576. func PruneLayers() error {
  577. deleteMap := make(map[string]struct{})
  578. p, err := GetBlobsPath("")
  579. if err != nil {
  580. return err
  581. }
  582. blobs, err := os.ReadDir(p)
  583. if err != nil {
  584. slog.Info(fmt.Sprintf("couldn't read dir '%s': %v", p, err))
  585. return err
  586. }
  587. for _, blob := range blobs {
  588. name := blob.Name()
  589. name = strings.ReplaceAll(name, "-", ":")
  590. if strings.HasPrefix(name, "sha256:") {
  591. deleteMap[name] = struct{}{}
  592. }
  593. }
  594. slog.Info(fmt.Sprintf("total blobs: %d", len(deleteMap)))
  595. err = deleteUnusedLayers(nil, deleteMap, false)
  596. if err != nil {
  597. return err
  598. }
  599. slog.Info(fmt.Sprintf("total unused blobs removed: %d", len(deleteMap)))
  600. return nil
  601. }
  602. func PruneDirectory(path string) error {
  603. info, err := os.Lstat(path)
  604. if err != nil {
  605. return err
  606. }
  607. if info.IsDir() && info.Mode()&os.ModeSymlink == 0 {
  608. entries, err := os.ReadDir(path)
  609. if err != nil {
  610. return err
  611. }
  612. for _, entry := range entries {
  613. if err := PruneDirectory(filepath.Join(path, entry.Name())); err != nil {
  614. return err
  615. }
  616. }
  617. entries, err = os.ReadDir(path)
  618. if err != nil {
  619. return err
  620. }
  621. if len(entries) > 0 {
  622. return nil
  623. }
  624. return os.Remove(path)
  625. }
  626. return nil
  627. }
  628. func DeleteModel(name string) error {
  629. mp := ParseModelPath(name)
  630. manifest, _, err := GetManifest(mp)
  631. if err != nil {
  632. return err
  633. }
  634. deleteMap := make(map[string]struct{})
  635. for _, layer := range manifest.Layers {
  636. deleteMap[layer.Digest] = struct{}{}
  637. }
  638. deleteMap[manifest.Config.Digest] = struct{}{}
  639. err = deleteUnusedLayers(&mp, deleteMap, false)
  640. if err != nil {
  641. return err
  642. }
  643. fp, err := mp.GetManifestPath()
  644. if err != nil {
  645. return err
  646. }
  647. err = os.Remove(fp)
  648. if err != nil {
  649. slog.Info(fmt.Sprintf("couldn't remove manifest file '%s': %v", fp, err))
  650. return err
  651. }
  652. return nil
  653. }
  654. func PushModel(ctx context.Context, name string, regOpts *registryOptions, fn func(api.ProgressResponse)) error {
  655. mp := ParseModelPath(name)
  656. fn(api.ProgressResponse{Status: "retrieving manifest"})
  657. if mp.ProtocolScheme == "http" && !regOpts.Insecure {
  658. return fmt.Errorf("insecure protocol http")
  659. }
  660. manifest, _, err := GetManifest(mp)
  661. if err != nil {
  662. fn(api.ProgressResponse{Status: "couldn't retrieve manifest"})
  663. return err
  664. }
  665. var layers []*Layer
  666. layers = append(layers, manifest.Layers...)
  667. layers = append(layers, manifest.Config)
  668. for _, layer := range layers {
  669. if err := uploadBlob(ctx, mp, layer, regOpts, fn); err != nil {
  670. slog.Info(fmt.Sprintf("error uploading blob: %v", err))
  671. return err
  672. }
  673. }
  674. fn(api.ProgressResponse{Status: "pushing manifest"})
  675. requestURL := mp.BaseURL()
  676. requestURL = requestURL.JoinPath("v2", mp.GetNamespaceRepository(), "manifests", mp.Tag)
  677. manifestJSON, err := json.Marshal(manifest)
  678. if err != nil {
  679. return err
  680. }
  681. headers := make(http.Header)
  682. headers.Set("Content-Type", "application/vnd.docker.distribution.manifest.v2+json")
  683. resp, err := makeRequestWithRetry(ctx, http.MethodPut, requestURL, headers, bytes.NewReader(manifestJSON), regOpts)
  684. if err != nil {
  685. return err
  686. }
  687. defer resp.Body.Close()
  688. fn(api.ProgressResponse{Status: "success"})
  689. return nil
  690. }
  691. func PullModel(ctx context.Context, name string, regOpts *registryOptions, fn func(api.ProgressResponse)) error {
  692. mp := ParseModelPath(name)
  693. var manifest *ManifestV2
  694. var err error
  695. var noprune string
  696. // build deleteMap to prune unused layers
  697. deleteMap := make(map[string]struct{})
  698. if noprune = os.Getenv("OLLAMA_NOPRUNE"); noprune == "" {
  699. manifest, _, err = GetManifest(mp)
  700. if err != nil && !errors.Is(err, os.ErrNotExist) {
  701. return err
  702. }
  703. if manifest != nil {
  704. for _, l := range manifest.Layers {
  705. deleteMap[l.Digest] = struct{}{}
  706. }
  707. deleteMap[manifest.Config.Digest] = struct{}{}
  708. }
  709. }
  710. if mp.ProtocolScheme == "http" && !regOpts.Insecure {
  711. return fmt.Errorf("insecure protocol http")
  712. }
  713. fn(api.ProgressResponse{Status: "pulling manifest"})
  714. manifest, err = pullModelManifest(ctx, mp, regOpts)
  715. if err != nil {
  716. return fmt.Errorf("pull model manifest: %s", err)
  717. }
  718. var layers []*Layer
  719. layers = append(layers, manifest.Layers...)
  720. layers = append(layers, manifest.Config)
  721. for _, layer := range layers {
  722. if err := downloadBlob(
  723. ctx,
  724. downloadOpts{
  725. mp: mp,
  726. digest: layer.Digest,
  727. regOpts: regOpts,
  728. fn: fn,
  729. }); err != nil {
  730. return err
  731. }
  732. delete(deleteMap, layer.Digest)
  733. }
  734. delete(deleteMap, manifest.Config.Digest)
  735. fn(api.ProgressResponse{Status: "verifying sha256 digest"})
  736. for _, layer := range layers {
  737. if err := verifyBlob(layer.Digest); err != nil {
  738. if errors.Is(err, errDigestMismatch) {
  739. // something went wrong, delete the blob
  740. fp, err := GetBlobsPath(layer.Digest)
  741. if err != nil {
  742. return err
  743. }
  744. if err := os.Remove(fp); err != nil {
  745. // log this, but return the original error
  746. slog.Info(fmt.Sprintf("couldn't remove file with digest mismatch '%s': %v", fp, err))
  747. }
  748. }
  749. return err
  750. }
  751. }
  752. fn(api.ProgressResponse{Status: "writing manifest"})
  753. manifestJSON, err := json.Marshal(manifest)
  754. if err != nil {
  755. return err
  756. }
  757. fp, err := mp.GetManifestPath()
  758. if err != nil {
  759. return err
  760. }
  761. if err := os.MkdirAll(filepath.Dir(fp), 0o755); err != nil {
  762. return err
  763. }
  764. err = os.WriteFile(fp, manifestJSON, 0o644)
  765. if err != nil {
  766. slog.Info(fmt.Sprintf("couldn't write to %s", fp))
  767. return err
  768. }
  769. if noprune == "" {
  770. fn(api.ProgressResponse{Status: "removing any unused layers"})
  771. err = deleteUnusedLayers(nil, deleteMap, false)
  772. if err != nil {
  773. return err
  774. }
  775. }
  776. fn(api.ProgressResponse{Status: "success"})
  777. return nil
  778. }
  779. func pullModelManifest(ctx context.Context, mp ModelPath, regOpts *registryOptions) (*ManifestV2, error) {
  780. requestURL := mp.BaseURL().JoinPath("v2", mp.GetNamespaceRepository(), "manifests", mp.Tag)
  781. headers := make(http.Header)
  782. headers.Set("Accept", "application/vnd.docker.distribution.manifest.v2+json")
  783. resp, err := makeRequestWithRetry(ctx, http.MethodGet, requestURL, headers, nil, regOpts)
  784. if err != nil {
  785. return nil, err
  786. }
  787. defer resp.Body.Close()
  788. var m *ManifestV2
  789. if err := json.NewDecoder(resp.Body).Decode(&m); err != nil {
  790. return nil, err
  791. }
  792. return m, err
  793. }
  794. // GetSHA256Digest returns the SHA256 hash of a given buffer and returns it, and the size of buffer
  795. func GetSHA256Digest(r io.Reader) (string, int64) {
  796. h := sha256.New()
  797. n, err := io.Copy(h, r)
  798. if err != nil {
  799. log.Fatal(err)
  800. }
  801. return fmt.Sprintf("sha256:%x", h.Sum(nil)), n
  802. }
  803. var errUnauthorized = fmt.Errorf("unauthorized: access denied")
  804. // getTokenSubject returns the subject of a JWT token, it does not validate the token
  805. func getTokenSubject(token string) string {
  806. parts := strings.Split(token, ".")
  807. if len(parts) != 3 {
  808. slog.Error("jwt token does not contain 3 parts")
  809. return ""
  810. }
  811. payload := parts[1]
  812. payloadBytes, err := base64.RawURLEncoding.DecodeString(payload)
  813. if err != nil {
  814. slog.Error(fmt.Sprintf("failed to decode jwt payload: %v", err))
  815. return ""
  816. }
  817. var payloadMap map[string]interface{}
  818. if err := json.Unmarshal(payloadBytes, &payloadMap); err != nil {
  819. slog.Error(fmt.Sprintf("failed to unmarshal payload JSON: %v", err))
  820. return ""
  821. }
  822. sub, ok := payloadMap["sub"]
  823. if !ok {
  824. slog.Error("jwt does not contain 'sub' field")
  825. return ""
  826. }
  827. return fmt.Sprintf("%s", sub)
  828. }
  829. func makeRequestWithRetry(ctx context.Context, method string, requestURL *url.URL, headers http.Header, body io.ReadSeeker, regOpts *registryOptions) (*http.Response, error) {
  830. anonymous := true // access will default to anonymous if no user is found associated with the public key
  831. for i := 0; i < 2; i++ {
  832. resp, err := makeRequest(ctx, method, requestURL, headers, body, regOpts)
  833. if err != nil {
  834. if !errors.Is(err, context.Canceled) {
  835. slog.Info(fmt.Sprintf("request failed: %v", err))
  836. }
  837. return nil, err
  838. }
  839. switch {
  840. case resp.StatusCode == http.StatusUnauthorized:
  841. // Handle authentication error with one retry
  842. challenge := parseRegistryChallenge(resp.Header.Get("www-authenticate"))
  843. token, err := getAuthorizationToken(ctx, challenge)
  844. if err != nil {
  845. return nil, err
  846. }
  847. anonymous = getTokenSubject(token) == "anonymous"
  848. regOpts.Token = token
  849. if body != nil {
  850. _, err = body.Seek(0, io.SeekStart)
  851. if err != nil {
  852. return nil, err
  853. }
  854. }
  855. case resp.StatusCode == http.StatusNotFound:
  856. return nil, os.ErrNotExist
  857. case resp.StatusCode >= http.StatusBadRequest:
  858. responseBody, err := io.ReadAll(resp.Body)
  859. if err != nil {
  860. return nil, fmt.Errorf("%d: %s", resp.StatusCode, err)
  861. }
  862. return nil, fmt.Errorf("%d: %s", resp.StatusCode, responseBody)
  863. default:
  864. return resp, nil
  865. }
  866. }
  867. if anonymous {
  868. // no user is associated with the public key, and the request requires non-anonymous access
  869. pubKey, nestedErr := auth.GetPublicKey()
  870. if nestedErr != nil {
  871. slog.Error(fmt.Sprintf("couldn't get public key: %v", nestedErr))
  872. return nil, errUnauthorized
  873. }
  874. return nil, &errtypes.UnknownOllamaKey{Key: pubKey}
  875. }
  876. // user is associated with the public key, but is not authorized to make the request
  877. return nil, errUnauthorized
  878. }
  879. func makeRequest(ctx context.Context, method string, requestURL *url.URL, headers http.Header, body io.Reader, regOpts *registryOptions) (*http.Response, error) {
  880. if requestURL.Scheme != "http" && regOpts != nil && regOpts.Insecure {
  881. requestURL.Scheme = "http"
  882. }
  883. req, err := http.NewRequestWithContext(ctx, method, requestURL.String(), body)
  884. if err != nil {
  885. return nil, err
  886. }
  887. if headers != nil {
  888. req.Header = headers
  889. }
  890. if regOpts != nil {
  891. if regOpts.Token != "" {
  892. req.Header.Set("Authorization", "Bearer "+regOpts.Token)
  893. } else if regOpts.Username != "" && regOpts.Password != "" {
  894. req.SetBasicAuth(regOpts.Username, regOpts.Password)
  895. }
  896. }
  897. req.Header.Set("User-Agent", fmt.Sprintf("ollama/%s (%s %s) Go/%s", version.Version, runtime.GOARCH, runtime.GOOS, runtime.Version()))
  898. if s := req.Header.Get("Content-Length"); s != "" {
  899. contentLength, err := strconv.ParseInt(s, 10, 64)
  900. if err != nil {
  901. return nil, err
  902. }
  903. req.ContentLength = contentLength
  904. }
  905. resp, err := http.DefaultClient.Do(req)
  906. if err != nil {
  907. return nil, err
  908. }
  909. return resp, nil
  910. }
  911. func getValue(header, key string) string {
  912. startIdx := strings.Index(header, key+"=")
  913. if startIdx == -1 {
  914. return ""
  915. }
  916. // Move the index to the starting quote after the key.
  917. startIdx += len(key) + 2
  918. endIdx := startIdx
  919. for endIdx < len(header) {
  920. if header[endIdx] == '"' {
  921. if endIdx+1 < len(header) && header[endIdx+1] != ',' { // If the next character isn't a comma, continue
  922. endIdx++
  923. continue
  924. }
  925. break
  926. }
  927. endIdx++
  928. }
  929. return header[startIdx:endIdx]
  930. }
  931. func parseRegistryChallenge(authStr string) registryChallenge {
  932. authStr = strings.TrimPrefix(authStr, "Bearer ")
  933. return registryChallenge{
  934. Realm: getValue(authStr, "realm"),
  935. Service: getValue(authStr, "service"),
  936. Scope: getValue(authStr, "scope"),
  937. }
  938. }
  939. var errDigestMismatch = errors.New("digest mismatch, file must be downloaded again")
  940. func verifyBlob(digest string) error {
  941. fp, err := GetBlobsPath(digest)
  942. if err != nil {
  943. return err
  944. }
  945. f, err := os.Open(fp)
  946. if err != nil {
  947. return err
  948. }
  949. defer f.Close()
  950. fileDigest, _ := GetSHA256Digest(f)
  951. if digest != fileDigest {
  952. return fmt.Errorf("%w: want %s, got %s", errDigestMismatch, digest, fileDigest)
  953. }
  954. return nil
  955. }